Merge hostapd upstream into master.

Current as of:
http://w1.fi/cgit/hostap/commit/?id=ca68a8b561c48393c8ba25055ce294caaa3ac008

Note that this resolves the merge conflicts, but does not compile.
A second commit on top of this one is needed to get a working hostapd.

Change-Id: Ib1f533ef8f3399aaec7d4bc6708f7ea126a2c39c
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index d20a556..ca09bae 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -112,7 +112,7 @@
 
 Modified BSD license (no advertisement clause):
 
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 8a98582..5962e2f 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 
diff --git a/README b/README
index 8de14a6..07d1d25 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
diff --git a/doc/Makefile b/doc/Makefile
index 4e1c1bd..62af04a 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -16,20 +16,23 @@
 _wpa_supplicant.png: wpa_supplicant.png
 	cp $< $@
 
-docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps
+_wpa_supplicant.eps: wpa_supplicant.eps
+	cp $< $@
+
+docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps _wpa_supplicant.png _wpa_supplicant.eps
 
 docs: docs-pics
 	(cd ..; doxygen doc/doxygen.conf; cd doc)
 	$(MAKE) -C latex
 	cp latex/refman.pdf wpa_supplicant-devel.pdf
 
-html: docs-pics _wpa_supplicant.png
+html: docs-pics
 	(cd ..; doxygen doc/doxygen.conf; cd doc)
 
 clean:
 	rm -f *~
 	rm -f wpa_supplicant.eps wpa_supplicant.png
-	rm -f _wpa_supplicant.png
+	rm -f _wpa_supplicant.png _wpa_supplicant.eps
 	rm -f hostapd.eps hostapd.png
 	rm -f p2p_sm.eps p2p_sm.png
 	rm -f p2p_arch.eps p2p_arch.png
diff --git a/doc/code_structure.doxygen b/doc/code_structure.doxygen
index 26f5f6d..454f179 100644
--- a/doc/code_structure.doxygen
+++ b/doc/code_structure.doxygen
@@ -13,7 +13,7 @@
 \ref win_port "Windows port" |
 \ref test_programs "Test programs" ]
 
-%wpa_supplicant implementation is divided into number of independent
+wpa_supplicant implementation is divided into number of independent
 modules. Core code includes functionality for controlling the network
 selection, association, and configuration. Independent modules include
 WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
@@ -21,82 +21,77 @@
 are number of separate files for generic helper functions.
 
 Both WPA and EAPOL/EAP state machines can be used separately in other
-programs than %wpa_supplicant. As an example, the included test
+programs than wpa_supplicant. As an example, the included test
 programs eapol_test and preauth_test are using these modules.
 
-\ref driver_wrapper "Driver interface API" is defined in driver.h and
+\ref driver_wrapper "Driver interface API" is defined in \ref driver.h and
 all hardware/driver dependent functionality is implemented in
 driver_*.c.
 
 
 \section _wpa_supplicant_core wpa_supplicant core functionality
 
-wpa_supplicant.c
+\ref wpa_supplicant.c
 	Program initialization, main control loop
 
-main.c
+\ref wpa_supplicant/main.c
 	main() for UNIX-like operating systems and MinGW (Windows); this
 	uses command line arguments to configure wpa_supplicant
 
-events.c
-	Driver event processing; wpa_supplicant_event() and related functions
+\ref events.c
+	Driver event processing; \ref wpa_supplicant_event() and related functions
 
-wpa_supplicant_i.h
-	Internal definitions for %wpa_supplicant core; should not be
+\ref wpa_supplicant_i.h
+	Internal definitions for wpa_supplicant core; should not be
 	included into independent modules
 
 
 \section generic_helper_func Generic helper functions
 
-%wpa_supplicant uses generic helper functions some of which are shared
+wpa_supplicant uses generic helper functions some of which are shared
 with with hostapd. The following C files are currently used:
 
-eloop.c and eloop.h
+\ref eloop.c and \ref eloop.h
 	Event loop (select() loop with registerable timeouts, socket read
 	callbacks, and signal callbacks)
 
-common.c and common.h
+\ref common.c and \ref common.h
 	Common helper functions
 
-defs.h
+\ref defs.h
 	Definitions shared by multiple files
 
-l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
+\ref l2_packet.h, \ref l2_packet_linux.c, and \ref l2_packet_pcap.c
 	Layer 2 (link) access wrapper (includes native Linux implementation
 	and wrappers for libdnet/libpcap). A new l2_packet implementation
 	may need to be added when porting to new operating systems that are
 	not supported by libdnet/libpcap. Makefile can be used to select which
-	l2_packet implementation is included. l2_packet_linux.c uses Linux
-	packet sockets and l2_packet_pcap.c has a more portable version using
+	l2_packet implementation is included. \ref l2_packet_linux.c uses Linux
+	packet sockets and \ref l2_packet_pcap.c has a more portable version using
 	libpcap and libdnet.
 
-pcsc_funcs.c and pcsc_funcs.h
+\ref pcsc_funcs.c and \ref pcsc_funcs.h
 	Wrapper for PC/SC lite SIM and smart card readers
 
-priv_netlink.h
+\ref priv_netlink.h
 	Private version of netlink definitions from Linux kernel header files;
 	this could be replaced with C library header file once suitable
 	version becomes commonly available
 
-version.h
+\ref version.h
 	Version number definitions
 
-wireless_copy.h
-	Private version of Linux wireless extensions definitions from kernel
-	header files; this could be replaced with C library header file once
-	suitable version becomes commonly available
-
 
 \section crypto_func Cryptographic functions
 
-md5.c and md5.h
+\ref md5.c and \ref md5.h
 	MD5 (replaced with a crypto library if TLS support is included)
 	HMAC-MD5 (keyed checksum for message authenticity validation)
 
-rc4.c and rc4.h
+\ref rc4.c and \ref rc4.h
 	RC4 (broadcast/default key encryption)
 
-sha1.c and sha1.h
+\ref sha1.c and \ref sha1.h
 	SHA-1 (replaced with a crypto library if TLS support is included)
 	HMAC-SHA-1 (keyed checksum for message authenticity validation)
 	PRF-SHA-1 (pseudorandom (key/nonce generation) function)
@@ -104,10 +99,10 @@
 	T-PRF (for EAP-FAST)
 	TLS-PRF (RFC 2246)
 
-sha256.c and sha256.h
+\ref sha256.c and \ref sha256.h
 	SHA-256 (replaced with a crypto library if TLS support is included)
 
-aes_wrap.c, aes_wrap.h, aes.c
+\ref aes-wrap.c, \ref aes_wrap.h, \ref aes.c
 	AES (replaced with a crypto library if TLS support is included),
 	AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
 	key encryption),
@@ -116,207 +111,205 @@
 	AES-128 EAX mode encryption/decryption,
 	AES-128 CBC
 
-crypto.h
+\ref crypto.h
 	Definition of crypto library wrapper
 
-crypto_openssl.c
+\ref crypto_openssl.c
 	Wrapper functions for libcrypto (OpenSSL)
 
-crypto_internal.c
+\ref crypto_internal.c
 	Wrapper functions for internal crypto implementation
 
-crypto_gnutls.c
+\ref crypto_gnutls.c
 	Wrapper functions for libgcrypt (used by GnuTLS)
 
-ms_funcs.c and ms_funcs.h
+\ref ms_funcs.c and \ref ms_funcs.h
 	Helper functions for MSCHAPV2 and LEAP
 
-tls.h
+\ref tls.h
 	Definition of TLS library wrapper
 
-tls_none.c
+\ref tls_none.c
 	Dummy implementation of TLS library wrapper for cases where TLS
 	functionality is not included.
 
-tls_openssl.c
+\ref tls_openssl.c
 	TLS library wrapper for openssl
 
-tls_internal.c
+\ref tls_internal.c
 	TLS library for internal TLS implementation
 
-tls_gnutls.c
+\ref tls_gnutls.c
 	TLS library wrapper for GnuTLS
 
 
 \section tls_func TLS library
 
-asn1.c and asn1.h
+\ref asn1.c and \ref asn1.h
 	ASN.1 DER parsing
 
-bignum.c and bignum.h
+\ref bignum.c and \ref bignum.h
 	Big number math
 
-rsa.c and rsa.h
+\ref rsa.c and \ref rsa.h
 	RSA
 
-x509v3.c and x509v3.h
+\ref x509v3.c and \ref x509v3.h
 	X.509v3 certificate parsing and processing
 
-tlsv1_client.c, tlsv1_client.h
+\ref tlsv1_client.c, \ref tlsv1_client.h
 	TLSv1 client (RFC 2246)
 
-tlsv1_client_i.h
+\ref tlsv1_client_i.h
 	Internal structures for TLSv1 client
 
-tlsv1_client_read.c
+\ref tlsv1_client_read.c
 	TLSv1 client: read handshake messages
 
-tlsv1_client_write.c
+\ref tlsv1_client_write.c
 	TLSv1 client: write handshake messages
 
-tlsv1_common.c and tlsv1_common.h
+\ref tlsv1_common.c and \ref tlsv1_common.h
 	Common TLSv1 routines and definitions
 
-tlsv1_cred.c and tlsv1_cred.h
+\ref tlsv1_cred.c and \ref tlsv1_cred.h
 	TLSv1 credentials
 
-tlsv1_record.c and tlsv1_record.h
+\ref tlsv1_record.c and \ref tlsv1_record.h
 	TLSv1 record protocol
 
 
 \section configuration Configuration
 
-config_ssid.h
+\ref config_ssid.h
 	Definition of per network configuration items
 
-config.h
-	Definition of the %wpa_supplicant configuration
+\ref config.h
+	Definition of the wpa_supplicant configuration
 
-config.c
+\ref config.c
 	Configuration parser and common functions
 
-config_file.c
+\ref wpa_supplicant/config_file.c
 	Configuration backend for text files (e.g., wpa_supplicant.conf)
 
-config_winreg.c
+\ref config_winreg.c
 	Configuration backend for Windows registry
 
 
 \section ctrl_iface Control interface
 
-%wpa_supplicant has a \ref ctrl_iface_page "control interface"
+wpa_supplicant has a \ref ctrl_iface_page "control interface"
 that can be used to get status
 information and manage operations from external programs. An example
 command line interface (wpa_cli) and GUI (wpa_gui) for this interface
-are included in the %wpa_supplicant distribution.
+are included in the wpa_supplicant distribution.
 
-ctrl_iface.c and ctrl_iface.h
-	%wpa_supplicant-side of the control interface
+\ref wpa_supplicant/ctrl_iface.c and \ref wpa_supplicant/ctrl_iface.h
+	wpa_supplicant-side of the control interface
 
-ctrl_iface_unix.c
+\ref ctrl_iface_unix.c
 	UNIX domain sockets -based control interface backend
 
-ctrl_iface_udp.c
+\ref ctrl_iface_udp.c
 	UDP sockets -based control interface backend
 
-ctrl_iface_named_pipe.c
+\ref ctrl_iface_named_pipe.c
 	Windows named pipes -based control interface backend
 
-wpa_ctrl.c and wpa_ctrl.h
+\ref wpa_ctrl.c and \ref wpa_ctrl.h
 	Library functions for external programs to provide access to the
-	%wpa_supplicant control interface
+	wpa_supplicant control interface
 
-wpa_cli.c
-	Example program for using %wpa_supplicant control interface
+\ref wpa_cli.c
+	Example program for using wpa_supplicant control interface
 
 
 \section wpa_code WPA supplicant
 
-wpa.c and wpa.h
+\ref wpa.c and \ref wpa.h
 	WPA state machine and 4-Way/Group Key Handshake processing
 
-preauth.c and preauth.h
+\ref preauth.c and \ref preauth.h
 	PMKSA caching and pre-authentication (RSN/WPA2)
 
-wpa_i.h
+\ref wpa_i.h
 	Internal definitions for WPA code; not to be included to other modules.
 
 \section eap_peer EAP peer
 
 \ref eap_peer_module "EAP peer implementation" is a separate module that
-can be used by other programs than just %wpa_supplicant.
+can be used by other programs than just wpa_supplicant.
 
-eap.c and eap.h
+\ref eap.c and \ref eap.h
 	EAP state machine and method interface
 
-eap_defs.h
+\ref eap_defs.h
 	Common EAP definitions
 
-eap_i.h
+\ref eap_i.h
 	Internal definitions for EAP state machine and EAP methods; not to be
 	included in other modules
 
-eap_sim_common.c and eap_sim_common.h
+\ref eap_sim_common.c and \ref eap_sim_common.h
 	Common code for EAP-SIM and EAP-AKA
 
-eap_tls_common.c and eap_tls_common.h
+\ref eap_tls_common.c and \ref eap_tls_common.h
 	Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
 
-eap_tlv.c and eap_tlv.h
-	EAP-TLV code for EAP-PEAP and EAP-FAST
-
-eap_ttls.c and eap_ttls.h
+\ref eap_ttls.c and \ref eap_ttls.h
 	EAP-TTLS
 
-eap_pax.c, eap_pax_common.h, eap_pax_common.c
+\ref eap_pax.c, \ref eap_pax_common.h, \ref eap_pax_common.c
 	EAP-PAX
 
-eap_psk.c, eap_psk_common.h, eap_psk_common.c
+\ref eap_psk.c, \ref eap_psk_common.h, \ref eap_psk_common.c
 	EAP-PSK (note: this is not needed for WPA-PSK)
 
-eap_sake.c, eap_sake_common.h, eap_sake_common.c
+\ref eap_sake.c, \ref eap_sake_common.h, \ref eap_sake_common.c
 	EAP-SAKE
 
-eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c
+\ref eap_gpsk.c, \ref eap_gpsk_common.h, \ref eap_gpsk_common.c
 	EAP-GPSK
 
-eap_aka.c, eap_fast.c, eap_gtc.c, eap_leap.c, eap_md5.c, eap_mschapv2.c,
-eap_otp.c, eap_peap.c, eap_sim.c, eap_tls.c
+\ref eap_aka.c, \ref eap_fast.c, \ref eap_gtc.c, \ref eap_leap.c,
+\ref eap_md5.c, \ref eap_mschapv2.c, \ref eap_otp.c, \ref eap_peap.c,
+\ref eap_sim.c, \ref eap_tls.c
 	Other EAP method implementations
 
 
 \section eapol_supp EAPOL supplicant
 
-eapol_supp_sm.c and eapol_supp_sm.h
+\ref eapol_supp_sm.c and \ref eapol_supp_sm.h
 	EAPOL supplicant state machine and IEEE 802.1X processing
 
 
 \section win_port Windows port
 
-ndis_events.c
+\ref ndis_events.c
 	Code for receiving NdisMIndicateStatus() events and delivering them to
-	%wpa_supplicant driver_ndis.c in more easier to use form
+	wpa_supplicant \ref driver_ndis.c in more easier to use form
 
-win_if_list.c
+\ref win_if_list.c
 	External program for listing current network interface
 
 
 \section test_programs Test programs
 
-radius_client.c and radius_client.h
+\ref radius_client.c and \ref radius_client.h
 	RADIUS authentication client implementation for eapol_test
 
-radius.c and radius.h
+\ref radius.c and \ref radius.h
 	RADIUS message processing for eapol_test
 
-eapol_test.c
+\ref eapol_test.c
 	Standalone EAP testing tool with integrated RADIUS authentication
 	client
 
-preauth_test.c
+\ref preauth_test.c
 	Standalone RSN pre-authentication tool
 
-wpa_passphrase.c
+\ref wpa_passphrase.c
 	WPA ASCII passphrase to PSK conversion
 
 */
diff --git a/doc/ctrl_iface.doxygen b/doc/ctrl_iface.doxygen
index 0d06625..be8916f 100644
--- a/doc/ctrl_iface.doxygen
+++ b/doc/ctrl_iface.doxygen
@@ -1,47 +1,47 @@
 /**
-\page ctrl_iface_page %wpa_supplicant control interface
+\page ctrl_iface_page wpa_supplicant control interface
 
-%wpa_supplicant implements a control interface that can be used by
-external programs to control the operations of the %wpa_supplicant
+wpa_supplicant implements a control interface that can be used by
+external programs to control the operations of the wpa_supplicant
 daemon and to get status information and event notifications. There is
-a small C library, in a form of a single C file, wpa_ctrl.c, that
+a small C library, in a form of a single C file, \ref wpa_ctrl.c, that
 provides helper functions to facilitate the use of the control
 interface. External programs can link this file into them and then use
-the library functions documented in wpa_ctrl.h to interact with
-%wpa_supplicant. This library can also be used with C++. wpa_cli.c and
+the library functions documented in \ref wpa_ctrl.h to interact with
+wpa_supplicant. This library can also be used with C++. \ref wpa_cli.c and
 wpa_gui are example programs using this library.
 
 There are multiple mechanisms for inter-process communication. For
-example, Linux version of %wpa_supplicant is using UNIX domain sockets
+example, Linux version of wpa_supplicant is using UNIX domain sockets
 for the control interface and Windows version UDP sockets. The use of
-the functions defined in wpa_ctrl.h can be used to hide the details of
+the functions defined in \ref wpa_ctrl.h can be used to hide the details of
 the used IPC from external programs.
 
 
 \section using_ctrl_iface Using the control interface
 
 External programs, e.g., a GUI or a configuration utility, that need to
-communicate with %wpa_supplicant should link in wpa_ctrl.c. This
+communicate with wpa_supplicant should link in \ref wpa_ctrl.c. This
 allows them to use helper functions to open connection to the control
-interface with wpa_ctrl_open() and to send commands with
-wpa_ctrl_request().
+interface with \ref wpa_ctrl_open() and to send commands with
+\ref wpa_ctrl_request().
 
-%wpa_supplicant uses the control interface for two types of communication:
+wpa_supplicant uses the control interface for two types of communication:
 commands and unsolicited event messages. Commands are a pair of
 messages, a request from the external program and a response from
-%wpa_supplicant. These can be executed using wpa_ctrl_request().
-Unsolicited event messages are sent by %wpa_supplicant to the control
+wpa_supplicant. These can be executed using \ref wpa_ctrl_request().
+Unsolicited event messages are sent by wpa_supplicant to the control
 interface connection without specific request from the external program
 for receiving each message. However, the external program needs to
-attach to the control interface with wpa_ctrl_attach() to receive these
+attach to the control interface with \ref wpa_ctrl_attach() to receive these
 unsolicited messages.
 
 If the control interface connection is used both for commands and
 unsolicited event messages, there is potential for receiving an
 unsolicited message between the command request and response.
-wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+\ref wpa_ctrl_request() caller will need to supply a callback, msg_cb,
 for processing these messages. Often it is easier to open two
-control interface connections by calling wpa_ctrl_open() twice and
+control interface connections by calling \ref wpa_ctrl_open() twice and
 then use one of the connections for commands and the other one for
 unsolicited messages. This way command request/response pairs will
 not be broken by unsolicited messages. wpa_cli is an example of how
@@ -49,20 +49,20 @@
 how to use two separate connections.
 
 Once the control interface connection is not needed anymore, it should
-be closed by calling wpa_ctrl_close(). If the connection was used for
+be closed by calling \ref wpa_ctrl_close(). If the connection was used for
 unsolicited event messages, it should be first detached by calling
-wpa_ctrl_detach().
+\ref wpa_ctrl_detach().
 
 
 \section ctrl_iface_cmds Control interface commands
 
-Following commands can be used with wpa_ctrl_request():
+Following commands can be used with \ref wpa_ctrl_request():
 
 \subsection ctrl_iface_PING PING
 
-This command can be used to test whether %wpa_supplicant is replying
+This command can be used to test whether wpa_supplicant is replying
 to the control interface commands. The expected reply is \c PONG if the
-connection is open and %wpa_supplicant is processing commands.
+connection is open and wpa_supplicant is processing commands.
 
 
 \subsection ctrl_iface_MIB MIB
@@ -217,13 +217,13 @@
 \subsection ctrl_iface_ATTACH ATTACH
 
 Attach the connection as a monitor for unsolicited events. This can
-be done with wpa_ctrl_attach().
+be done with \ref wpa_ctrl_attach().
 
 
 \subsection ctrl_iface_DETACH DETACH
 
 Detach the connection as a monitor for unsolicited events. This can
-be done with wpa_ctrl_detach().
+be done with \ref wpa_ctrl_detach().
 
 
 \subsection ctrl_iface_LEVEL LEVEL <debug level>
@@ -233,12 +233,12 @@
 
 \subsection ctrl_iface_RECONFIGURE RECONFIGURE
 
-Force %wpa_supplicant to re-read its configuration data.
+Force wpa_supplicant to re-read its configuration data.
 
 
 \subsection ctrl_iface_TERMINATE TERMINATE
 
-Terminate %wpa_supplicant process.
+Terminate wpa_supplicant process.
 
 
 \subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
@@ -563,7 +563,7 @@
 
 \section ctrl_iface_interactive Interactive requests
 
-If %wpa_supplicant needs additional information during authentication
+If wpa_supplicant needs additional information during authentication
 (e.g., password), it will use a specific prefix, \c CTRL-REQ-
 (\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
 program, e.g., a GUI, can provide such information by using
@@ -583,7 +583,7 @@
 CTRL-RSP-<field name>-<network id>-<value>
 \endverbatim
 
-For example, request from %wpa_supplicant:
+For example, request from wpa_supplicant:
 \verbatim
 CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
 \endverbatim
@@ -598,7 +598,7 @@
 
 Get list of supported functionality (eap, pairwise, group,
 proto). Supported functionality is shown as space separate lists of
-values used in the same format as in %wpa_supplicant configuration.
+values used in the same format as in wpa_supplicant configuration.
 If optional argument, 'strict', is added, only the values that the
 driver claims to explicitly support are included. Without this, all
 available capabilities are included if the driver does not provide
@@ -645,8 +645,8 @@
 
 Change ap_scan value:
 0 = no scanning,
-1 = %wpa_supplicant requests scans and uses scan results to select the AP,
-2 = %wpa_supplicant does not use scanning and just requests driver to
+1 = wpa_supplicant requests scans and uses scan results to select the AP,
+2 = wpa_supplicant does not use scanning and just requests driver to
 associate and take care of AP selection
 
 
@@ -662,14 +662,14 @@
 
 \section ctrl_iface_events Control interface events
 
-%wpa_supplicant generates number messages based on events like
+wpa_supplicant generates number messages based on events like
 connection or a completion of a task. These are available to external
 programs that attach to receive unsolicited messages over the control
-interface with wpa_ctrl_attach().
+interface with \ref wpa_ctrl_attach().
 
 The event messages will be delivered over the attach control interface
 as text strings that start with the priority level of the message and
-a fixed prefix text as defined in wpa_ctrl.h. After this, optional
+a fixed prefix text as defined in \ref wpa_ctrl.h. After this, optional
 additional information may be included depending on the event
 message. For example, following event message is delivered when new
 scan results are available:
@@ -694,11 +694,11 @@
 
 In most cases, the external program can skip over the priority field
 in the beginning of the event message and then compare the following
-text to the event strings from wpa_ctrl.h that the program is
+text to the event strings from \ref wpa_ctrl.h that the program is
 interested in processing.
 
 Following subsections describe the most common event notifications
-generated by %wpa_supplicant.
+generated by wpa_supplicant.
 
 \subsection ctrl_iface_event_CTRL_REQ CTRL-REQ-
 
@@ -717,7 +717,7 @@
 
 \subsection ctrl_iface_event_TERMINATING  CTRL-EVENT-TERMINATING
 
-WPA_EVENT_TERMINATING: %wpa_supplicant is exiting
+WPA_EVENT_TERMINATING: wpa_supplicant is exiting
 
 \subsection ctrl_iface_event_PASSWORD_CHANGED CTRL-EVENT-PASSWORD-CHANGED
 
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 02c7407..329e5d0 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -1,8 +1,8 @@
 /**
-\page dbus %wpa_supplicant D-Bus API
+\page dbus wpa_supplicant D-Bus API
 
-This section documents the %wpa_supplicant D-Bus API. Every D-Bus
-interface implemented by %wpa_supplicant is described here including
+This section documents the wpa_supplicant D-Bus API. Every D-Bus
+interface implemented by wpa_supplicant is described here including
 their methods, signals, and properties with arguments, returned
 values, and possible errors.
 
@@ -10,13 +10,17 @@
 - \ref dbus_main
 - \ref dbus_interface
 - \ref dbus_wps
+- \ref dbus_p2pdevice
 - \ref dbus_bss
 - \ref dbus_network
+- \ref dbus_peer
+- \ref dbus_group
+- \ref dbus_persistent_group
 
 
 \section dbus_main fi.w1.wpa_supplicant1
 
-Interface implemented by the main %wpa_supplicant D-Bus object
+Interface implemented by the main wpa_supplicant D-Bus object
 registered in the bus with fi.w1.wpa_supplicant1 name.
 
 \subsection dbus_main_methods Methods
@@ -24,12 +28,12 @@
 <ul>
       <li>
 	<h3>CreateInterface ( a{sv} : args ) --> o : interface</h3>
-	<p>Registers a wireless interface in %wpa_supplicant.</p>
+	<p>Registers a wireless interface in wpa_supplicant.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>a{sv} : args</dt>
 	  <dd>
-	    A dictionary with arguments used to add the interface to %wpa_supplicant. The dictionary may contain the following entries:
+	    A dictionary with arguments used to add the interface to wpa_supplicant. The dictionary may contain the following entries:
 	    <table>
 	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
 	      <tr><td>Ifname</td><td>s</td><td>Name of the network interface to control, e.g., wlan0</td><td>Yes</td>
@@ -47,7 +51,7 @@
 	<h4>Possible errors</h4>
 	<dl>
 	  <dt>fi.w1.wpa_supplicant1.InterfaceExists</dt>
-	  <dd>%wpa_supplicant already controls this interface.</dd>
+	  <dd>wpa_supplicant already controls this interface.</dd>
 	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
 	  <dd>Creating interface failed for an unknown reason.</dd>
 	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
@@ -57,7 +61,7 @@
 
       <li>
 	<h3>RemoveInterface ( o : interface ) --> nothing</h3>
-	<p>Deregisters a wireless interface from %wpa_supplicant.</p>
+	<p>Deregisters a wireless interface from wpa_supplicant.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>o : interface</dt>
@@ -74,7 +78,7 @@
 
       <li>
 	<h3>GetInterface ( s : ifname ) --> o : interface</h3>
-	<p>Returns a D-Bus path to an object related to an interface which %wpa_supplicant already controls.</p>
+	<p>Returns a D-Bus path to an object related to an interface which wpa_supplicant already controls.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>s : ifname</dt>
@@ -88,7 +92,7 @@
 	<h4>Possible errors</h4>
 	<dl>
 	  <dt>fi.w1.wpa_supplicant1.InterfaceUnknown</dt>
-	  <dd>An interface with the passed name in not controlled by %wpa_supplicant.</dd>
+	  <dd>An interface with the passed name in not controlled by wpa_supplicant.</dd>
 	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
 	  <dd>Getting an interface object path failed for an unknown reason.</dd>
 	</dl>
@@ -100,19 +104,19 @@
 <ul>
       <li>
 	<h3>DebugLevel - s - (read/write)</h3>
-	<p>Global %wpa_supplicant debugging level. Possible values are
+	<p>Global wpa_supplicant debugging level. Possible values are
 	"msgdump" (verbose debugging), "debug" (debugging),
 	"info" (informative), "warning" (warnings), and "error" (errors).</p>
       </li>
 
       <li>
 	<h3>DebugTimestamp - b - (read/write)</h3>
-	<p>Global %wpa_supplicant debugging parameter. Determines if timestamps are shown in debug logs.</p>
+	<p>Global wpa_supplicant debugging parameter. Determines if timestamps are shown in debug logs.</p>
       </li>
 
       <li>
 	<h3>DebugShowKeys - b - (read/write)</h3>
-	<p>Global %wpa_supplicant debugging parameter. Determines if secrets are shown in debug logs.</p>
+	<p>Global wpa_supplicant debugging parameter. Determines if secrets are shown in debug logs.</p>
       </li>
 
       <li>
@@ -129,6 +133,11 @@
 	<h3>Capabilities - as - (read)</h3>
 	<p>An array with supported capabilities (e.g., "ap", "ibss-rsn", "p2p", "interworking").</p>
       </li>
+
+      <li>
+	<h3>WFDIEs - ay - (read/write)</h3>
+	<p>Wi-Fi Display subelements.</p>
+      </li>
     </ul>
 
 \subsection dbus_main_signals Signals
@@ -136,7 +145,7 @@
 <ul>
       <li>
 	<h3>InterfaceAdded ( o : interface, a{sv} : properties )</h3>
-	<p>A new interface was added to %wpa_supplicant.</p>
+	<p>A new interface was added to wpa_supplicant.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>o : interface</dt>
@@ -150,7 +159,7 @@
 
       <li>
 	<h3>InterfaceRemoved ( o : interface )</h3>
-	<p>An interface was removed from %wpa_supplicant.</p>
+	<p>An interface was removed from wpa_supplicant.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>o : interface</dt>
@@ -173,7 +182,7 @@
 \section dbus_interface fi.w1.wpa_supplicant1.Interface
 
 Interface implemented by objects related to network interface added to
-%wpa_supplicant, i.e., returned by
+wpa_supplicant, i.e., returned by
 fi.w1.wpa_supplicant1.CreateInterface.
 
 \subsection dbus_interface_methods Methods
@@ -220,7 +229,7 @@
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>a{sv} : args</dt>
-	  <dd>A dictionary with network configuration. Dictionary entries are equivalent to entries in the "network" block in %wpa_supplicant configuration file. Entry values should be appropriate type to the entry, e.g., an entry with key "frequency" should have value type int.</dd>
+	  <dd>A dictionary with network configuration. Dictionary entries are equivalent to entries in the "network" block in wpa_supplicant configuration file. Entry values should be appropriate type to the entry, e.g., an entry with key "frequency" should have value type int.</dd>
 	</dl>
 	<h4>Returns</h4>
 	<dl>
@@ -511,6 +520,30 @@
 	  <dd>Maximum age in seconds for BSS entries to keep in cache (0 = remove all entries).</dd>
 	</dl>
       </li>
+
+      <li>
+	<h3>SubscribeProbeReq ( ) --> nothing</h3>
+	<p>Subscribe to receive Probe Request events. This is needed in addition to registering a signal handler for the ProbeRequest signal to avoid flooding D-Bus with all Probe Request indications when no application is interested in them.</p>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.SubscriptionInUse</dt>
+	  <dd>Another application is already subscribed.</dd>
+	  <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+	  <dd>Needed memory was not possible to get allocated.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>UnsubscribeProbeReq ( ) --> nothing</h3>
+	<p>Unsubscribe from receiving Probe Request events.</p>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.NoSubscription</dt>
+	  <dd>No subscription in place.</dd>
+	  <dt>fi.w1.wpa_supplicant1.SubscriptionNotYou</dt>
+	  <dd>Subscription in place, but for another process.</dd>
+	</dl>
+      </li>
     </ul>
 
 \subsection dbus_interface_properties Properties
@@ -543,22 +576,22 @@
 
       <li>
 	<h3>ApScan - u - (read/write)</h3>
-	<p>Identical to ap_scan entry in %wpa_supplicant configuration file. Possible values are 0, 1 or 2.</p>
+	<p>Identical to ap_scan entry in wpa_supplicant configuration file. Possible values are 0, 1 or 2.</p>
       </li>
 
       <li>
 	<h3>BSSExpireAge - u - (read/write)</h3>
-	<p>Identical to bss_expiration_age entry in %wpa_supplicant configuration file.</p>
+	<p>Identical to bss_expiration_age entry in wpa_supplicant configuration file.</p>
       </li>
 
       <li>
 	<h3>BSSExpireCount - u - (read/write)</h3>
-	<p>Identical to bss_expiration_scan_count entry in %wpa_supplicant configuration file.</p>
+	<p>Identical to bss_expiration_scan_count entry in wpa_supplicant configuration file.</p>
       </li>
 
       <li>
 	<h3>Country - s - (read/write)</h3>
-	<p>Identical to country entry in %wpa_supplicant configuration file.</p>
+	<p>Identical to country entry in wpa_supplicant configuration file.</p>
       </li>
 
       <li>
@@ -578,12 +611,17 @@
 
       <li>
 	<h3>CurrentBSS - o - (read)</h3>
-	<p>Path to D-Bus object representing BSS which %wpa_supplicant is associated with, or "/" if is not associated at all.</p>
+	<p>Path to D-Bus object representing BSS which wpa_supplicant is associated with, or "/" if is not associated at all.</p>
       </li>
 
       <li>
 	<h3>CurrentNetwork - o - (read)</h3>
-	<p>Path to D-Bus object representing configured network which %wpa_supplicant uses at the moment, or "/" if doesn't use any.</p>
+	<p>Path to D-Bus object representing configured network which wpa_supplicant uses at the moment, or "/" if doesn't use any.</p>
+      </li>
+
+      <li>
+	<h3>CurrentAuthMode - s - (read)</h3>
+	<p>Current authentication type.</p>
       </li>
 
       <li>
@@ -603,7 +641,7 @@
 
       <li>
 	<h3>FastReauth - b - (read/write)</h3>
-	<p>Identical to fast_reauth entry in %wpa_supplicant configuration file.</p>
+	<p>Identical to fast_reauth entry in wpa_supplicant configuration file.</p>
       </li>
 
       <li>
@@ -620,6 +658,11 @@
 	<h3>PKCS11ModulePath - s - (read)</h3>
 	<p>PKCS #11 module path.</p>
       </li>
+
+      <li>
+	<h3>DisconnectReason - i - (read)</h3>
+	<p>The most recent IEEE 802.11 reason code for disconnect. Negative value indicates locally generated disconnection.</p>
+      </li>
     </ul>
 
 \subsection dbus_interface_signals Signals
@@ -749,7 +792,7 @@
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>a{sv} : parameters</dt>
-	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "cert_hash", "cert".</dd>
+	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "altsubject", "cert_hash", "cert".</dd>
 	</dl>
       </li>
 
@@ -778,20 +821,29 @@
 	  <dd>Human readable information about the requested information.</dd>
 	</dl>
       </li>
+
+      <li>
+	<h3>ProbeRequest ( a{sv} : args )</h3>
+	<p>Information about a received Probe Request frame. This signal is delivered only to a single application that has subscribed to received the events with SubscribeProbeReq().</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : args</dt>
+	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "addr", "dst", "bssid", "ies", "signal".</dd>
+	</dl>
+      </li>
     </ul>
 
 
 \section dbus_wps fi.w1.wpa_supplicant1.Interface.WPS
 
-Interface implemented by objects related to network interface added to
-%wpa_supplicant, i.e., returned by fi.w1.wpa_supplicant1.CreateInterface.
+Interface for performing WPS (Wi-Fi Simple Config) operations.
 
 \subsection dbus_wps_methods Methods
 
 <ul>
       <li>
 	<h3>Start ( a{sv} : args ) --> a{sv} : output</h3>
-	<p>Starts WPS configuration.</p>
+	<p>Starts WPS configuration. Note: When used with P2P groups, this needs to be issued on the GO group interface.</p>
 	<h4>Arguments</h4>
 	<dl>
 	  <dt>a{sv} : args</dt>
@@ -802,7 +854,8 @@
 	      <tr><td>Role</td><td>s</td><td>The device's role. Possible values are "enrollee" and "registrar".</td><td>Yes</td>
 	      <tr><td>Type</td><td>s</td><td>WPS authentication type. Applies only for enrollee role. Possible values are "pin" and "pbc".</td><td>Yes, for enrollee role; otherwise no</td>
 	      <tr><td>Pin</td><td>s</td><td>WPS Pin.</td><td>Yes, for registrar role; otherwise optional</td>
-	      <tr><td>Bssid</td><td>ay</td><td></td><td>No</td>
+	      <tr><td>Bssid</td><td>ay</td><td>Note: This is used to specify the peer MAC address when authorizing WPS connection in AP or P2P GO role.</td><td>No</td>
+	      <tr><td>P2PDeviceAddress</td><td>ay</td><td>P2P Device Address of a peer to authorize for PBC connection. Used only in P2P GO role.</td><td>No</td>
 	    </table>
 	  </dd>
 	</dl>
@@ -833,6 +886,10 @@
 	<h3>ProcessCredentials - b - (read/write)</h3>
 	<p>Determines if the interface will process the credentials (credentials_processed configuration file parameter).</p>
       </li>
+      <li>
+	<h3>ConfigMethods - s - (read/write)</h3>
+	<p>The currently advertised WPS configuration methods. Available methods: usba ethernet label display ext_nfc_token int_nfc_token nfc_interface push_button keypad virtual_display physical_display virtual_push_button physical_push_button.</p>
+      </li>
     </ul>
 
 \subsection dbus_wps_signals Signals
@@ -889,6 +946,553 @@
     </ul>
 
 
+\section dbus_p2pdevice fi.w1.wpa_supplicant1.Interface.P2PDevice
+
+Interface for performing P2P (Wi-Fi Peer-to-Peer) P2P Device operations.
+
+\subsection dbus_p2pdevice_methods Methods
+
+<ul>
+  <li>
+    <h3>Find ( a{sv} : args ) --> nothing</h3>
+    <p>Start P2P find operation (i.e., alternating P2P Search and Listen states to discover peers and be discoverable).</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the P2P find operation:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>Timeout</td><td>i</td><td>Timeout for operating in seconds</td><td>no</td></tr>
+	<tr><td>RequestedDevicesTypes</td><td>aay</td><td>WPS Device Types to search for</td><td>no</td></tr>
+	<tr><td>DiscoveryType</td><td>s</td><td>"start_with_full" (default, if not specified), "social", "progressive"</td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>StopFind ( nothing ) --> nothing</h3>
+    <p>Stop P2P find operation.</p>
+  </li>
+
+  <li>
+    <h3>Listen ( i : timeout ) --> nothing</h3>
+    <p>Start P2P listen operation (i.e., be discoverable).</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>i : timeout</dt>
+      <dd>Timeout in seconds for stopping the listen operation.</dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ExtendedListen ( a{sv} : args ) --> nothing</h3>
+    <p>Configure Extended Listen Timing. If the parameters are omitted, this feature is disabled. If the parameters are included, Listen State will be entered every interval msec for at least period msec. Both values have acceptable range of 1-65535 (with interval obviously having to be larger than or equal to duration). If the P2P module is not idle at the time the Extended Listen Timing timeout occurs, the Listen State operation will be skipped.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for extended listen. Leave out all items to disable extended listen.
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>period</td><td>i</td><td>Extended listen period in milliseconds; 1-65535.</td><td>no</td></tr>
+	<tr><td>interval</td><td>i</td><td>Extended listen interval in milliseconds; 1-65535.</td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>PresenceRequest ( a{sv} : args ) --> nothing</h3>
+    <p>Request a specific GO presence in a P2P group where the local device is a P2P Client. Send a P2P Presence Request to the GO (this is only available when acting as a P2P client). If no duration/interval pairs are given, the request indicates that this client has no special needs for GO presence. The first parameter pair gives the preferred duration and interval values in microseconds. If the second pair is included, that indicates which value would be acceptable.
+    \note This needs to be issued on a P2P group interface if separate group interfaces are used.
+    \bug It would be cleaner to not require .P2PDevice methods to be issued on a group interface. In other words, args['group_object'] could be used to specify the group or this method could be moved to be a .Group PresenceRequest() method.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the presence request.
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>duration1</td><td>i</td><td>Duration in microseconds.</td><td>no</td></tr>
+	<tr><td>interval1</td><td>i</td><td>Interval in microseconds.</td><td>no</td></tr>
+	<tr><td>duration2</td><td>i</td><td>Duration in microseconds.</td><td>no</td></tr>
+	<tr><td>interval2</td><td>i</td><td>Interval in microseconds.</td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryRequest ( o : peer, s : config_method ) --> nothing</h3>
+  </li>
+
+  <li>
+    <h3>Connect ( a{sv} : args ) --> s : generated_pin</h3>
+    <p>Request a P2P group to be started through GO Negotiation or by joining an already operating group.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the requested connection:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>peer</td><td>o</td><td></td><td>yes</td></tr>
+	<tr><td>persistent</td><td>b</td><td>Whether to form a persistent group.</td><td>no</td></tr>
+	<tr><td>join</td><td>b</td><td>Whether to join an already operating group instead of forming a new group.</td><td>no</td></tr>
+	<tr><td>authorize_only</td><td>b</td><td>Whether to authorize a peer to initiate GO Negotiation instead of initiating immediately.</td><td>no</td></tr>
+	<tr><td>frequency</td><td>i</td><td>Operating frequency in MHz</td><td>no</td></tr>
+	<tr><td>go_intent</td><td>i</td><td>GO intent 0-15</td><td>no</td></tr>
+	<tr><td>wps_method</td><td>s</td><td>"pbc", "display", "keypad", "pin" (alias for "display")</td><td>yes</td></tr>
+	<tr><td>pin</td><td>s</td><td></td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>GroupAdd ( a{sv} : args ) --> nothing</h3>
+    <p>Request a P2P group to be started without GO Negotiation.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the requested group:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>persistent</td><td>b</td><td>Whether to form a persistent group.</td><td>no</td></tr>
+	<tr><td>persistent_group_object</td><td>o</td><td></td><td>no</td></tr>
+	<tr><td>frequency</td><td>i</td><td>Operating frequency in MHz</td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>Invite ( a{sv} : args ) --> nothing</h3>
+    <p>Invite a peer to join an already operating group or to re-invoke a persistent group.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the invitation:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>peer</td><td>o</td><td></td><td>yes</td></tr>
+	<tr><td>persistent_group_object</td><td>o</td><td></td><td>no</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>Disconnect ( nothing ) --> nothing</h3>
+    <p>Terminate a P2P group.
+    \note This needs to be issued on a P2P group interface if separate group interfaces are used.
+    \bug It would be cleaner to not require .P2PDevice methods to be issued on a group interface. In other words, this would either need to be Disconnect(group_object) or moved to be a .Group Disconnect() method.</p>
+  </li>
+
+  <li>
+    <h3>RejectPeer ( o : peer ) --> nothing</h3>
+    <p>Reject connection attempt from a peer (specified with a device address). This is a mechanism to reject a pending GO Negotiation with a peer and request to automatically block any further connection or discovery of the peer.</p>
+  </li>
+
+  <li>
+    <h3>Flush ( nothing ) --> nothing</h3>
+    <p>Flush P2P peer table and state.</p>
+  </li>
+
+  <li>
+    <h3>AddService ( a{sv} : args ) --> nothing</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the service:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>service_type</td><td>s</td><td>"upnp", "bonjour"</td><td>yes</td></tr>
+	<tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+	<tr><td>service</td><td>s</td><td></td><td></td></tr>
+	<tr><td>query</td><td>ay</td><td></td><td></td></tr>
+	<tr><td>response</td><td>ay</td><td></td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>DeleteService ( a{sv} : args ) --> nothing</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with parameters for the service:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>service_type</td><td>s</td><td>"upnp", "bonjour"</td><td>yes</td></tr>
+	<tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+	<tr><td>service</td><td>s</td><td></td><td></td></tr>
+	<tr><td>query</td><td>ay</td><td></td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>FlushService ( nothing ) --> nothing</h3>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryRequest ( a{sv} : args ) --> t : ref</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with following parameters:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>peer_object</td><td>o</td><td></td><td>no</td></tr>
+	<tr><td>service_type</td><td>s</td><td>"upnp"</td><td>no</td></tr>
+	<tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+	<tr><td>service</td><td>s</td><td></td><td></td></tr>
+	<tr><td>tlv</td><td>ay</td><td></td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryResponse ( a{sv} : args ) --> nothing : ref</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with following parameters:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>peer_object</td><td>o</td><td></td><td>yes</td></tr>
+	<tr><td>frequency</td><td>i</td><td></td><td>yes</td></tr>
+	<tr><td>dialog_token</td><td>i</td><td></td><td>yes</td></tr>
+	<tr><td>tlvs</td><td>ay</td><td></td><td>yes</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryCancelRequest ( t : args ) --> nothing : ref</h3>
+  </li>
+
+  <li>
+    <h3>ServiceUpdate ( nothing ) --> nothing</h3>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryExternal ( i : arg ) --> nothing</h3>
+  </li>
+
+  <li>
+    <h3>AddPersistentGroup ( a{sv} : args ) --> o : path</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : args</dt>
+      <dd>
+	A dictionary with following parameters:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+	<tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td><td>yes</td></tr>
+	<tr><td>ssid</td><td>s</td><td>SSID of the group</td><td>yes</td></tr>
+	<tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td><td>yes</td></tr>
+	<tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td><td>yes</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>RemovePersistentGroup ( o : path ) --> nothing</h3>
+  </li>
+
+  <li>
+    <h3>RemoveAllPersistentGroups ( nothing ) --> nothing</h3>
+  </li>
+</ul>
+
+\subsection dbus_p2pdevice_properties Properties
+
+<ul>
+  <li>
+    <h3>P2PDeviceConfig - a{sv} - (read/write)</h3>
+    <p>Dictionary with following entries. On write, only the included values are changed.</p>
+    <table>
+    <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+    <tr><td>DeviceName</td><td>s</td><td></td></tr>
+    <tr><td>PrimaryDeviceType</td><td>ay</td><td></td></tr>
+    <tr><td>SecondaryDeviceTypes</td><td>aay</td><td></td></tr>
+    <tr><td>VendorExtension</td><td>aay</td><td></td></tr>
+    <tr><td>GOIntent</td><td>u</td><td></td></tr>
+    <tr><td>PersistentReconnect</td><td>b</td><td></td></tr>
+    <tr><td>ListenRegClass</td><td>u</td><td></td></tr>
+    <tr><td>OperRegClass</td><td>u</td><td></td></tr>
+    <tr><td>OperChannel</td><td>u</td><td></td></tr>
+    <tr><td>SsidPostfix</td><td>s</td><td></td></tr>
+    <tr><td>IntraBss</td><td>b</td><td></td></tr>
+    <tr><td>GroupIdle</td><td>u</td><td></td></tr>
+    <tr><td>disassoc_low_ack</td><td>u</td><td></td></tr>
+    <tr><td>NoGroupIface</td><td>b</td><td></td></tr>
+    <tr><td>p2p_search_delay</td><td>u</td><td></td></tr>
+    </table>
+  </li>
+
+  <li>
+    <h3>Peers - ao - (read)</h3>
+  </li>
+
+  <li>
+    <h3>Role - s - (read)</h3>
+    <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property role since there can be multiple concurrent groups and the P2P Device role is always active anyway.</p>
+  </li>
+
+  <li>
+    <h3>Group - o - (read)</h3>
+    <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property Group since there can be multiple concurrent groups.</p>
+  </li>
+
+  <li>
+    <h3>PeerGO - o - (read)</h3>
+    <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property PeerGO since there can be multiple concurrent groups.</p>
+  </li>
+
+  <li>
+    <h3>PersistentGroups - ao - (read)</h3>
+  </li>
+</ul>
+
+\subsection dbus_p2pdevice_signals Signals
+
+<ul>
+  <li>
+    <h3>DeviceFound ( o : path )</h3>
+  </li>
+
+  <li>
+    <h3>DeviceLost ( o : path )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryRequestDisplayPin ( o : peer_object, s : pin )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryResponseDisplayPin ( o : peer_object, s : pin )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryRequestEnterPin ( o : peer_object )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryResponseEnterPin ( o : peer_object )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryPBCRequest ( o : peer_object )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryPBCResponse ( o : peer_object )</h3>
+  </li>
+
+  <li>
+    <h3>ProvisionDiscoveryFailure ( o : peer_object, i : status )</h3>
+  </li>
+
+  <li>
+    <h3>GroupStarted ( a{sv} : properties )</h3>
+    <p>A new P2P group was started or joined.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary with following information on the added group:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>interface_object</td><td>o</td><td>D-Bus path of the interface on which this group is operating on. See \ref dbus_interface.</td></tr>
+	  <tr><td>role</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+	  <tr><td>group_object</td><td>o</td><td>D-Bus path of the group. See \ref dbus_group.</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>GONegotiationSuccess ( a{sv} : properties )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>peer_object</td><td>o</td><td>D-Bus path of the peer. See \ref dbus_peer.</td></tr>
+	  <tr><td>status</td><td>i</td><td></td></tr>
+	  <tr><td>passphrase</td><td>s</td><td>Passphrase for the group. Included only if this device becomes the GO of the group.</td></tr>
+	  <tr><td>role_go</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+	  <tr><td>ssid</td><td>ay</td><td></td></tr>
+	  <tr><td>peer_device_addr</td><td>ay</td><td></td></tr>
+	  <tr><td>peer_interface_addr</td><td>ay</td><td></td></tr>
+	  <tr><td>wps_method</td><td>s</td><td></td></tr>
+	  <tr><td>frequency_list</td><td>ai</td><td></td></tr>
+	  <tr><td>persistent_group</td><td>i</td><td></td></tr>
+	  <tr><td>peer_config_timeout</td><td>u</td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>GONegotiationFailure ( a{sv} : properties )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>peer_object</td><td>o</td><td>D-Bus path of the peer. See \ref dbus_peer.</td></tr>
+	  <tr><td>status</td><td>i</td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>GONegotiationRequest ( o : path, i : dev_passwd_id )</h3>
+  </li>
+
+  <li>
+    <h3>InvitationResult ( a{sv} : invite_result )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : invite_result</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>status</td><td>i</td><td></td></tr>
+	  <tr><td>BSSID</td><td>ay</td><td>Optionally present</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>GroupFinished ( a{sv} : properties )</h3>
+    <p>A P2P group was removed.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary with following information of the removed group:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>interface_object</td><td>o</td><td>D-Bus path of the interface on which this group is operating on. See \ref dbus_interface.</td></tr>
+	  <tr><td>role</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+	  <tr><td>group_object</td><td>o</td><td>D-Bus path of the group. See \ref dbus_group.</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryRequest ( a{sv} : sd_request )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : sd_request</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><td>peer_object</td><td>o</td><td></td></tr>
+	  <tr><td>frequency</td><td>i</td><td></td></tr>
+	  <tr><td>dialog_token</td><td>i</td><td></td></tr>
+	  <tr><td>update_indicator</td><td>q</td><td></td></tr>
+	  <tr><td>tlvs</td><td>ay</td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>ServiceDiscoveryResponse ( a{sv} : sd_response )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>a{sv} : sd_response</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><td>peer_object</td><td>o</td><td></td></tr>
+	  <tr><td>update_indicator</td><td>q</td><td></td></tr>
+	  <tr><td>tlvs</td><td>ay</td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>PersistentGroupAdded ( o : path, a{sv} : properties )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>o : path</dt>
+      <dd>D-Bus object path for the persistent group. See \ref dbus_persistent_group.</dd>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary with following information:
+	<table>
+	<tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	<tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td></tr>
+	<tr><td>ssid</td><td>s</td><td>SSID of the group</td></tr>
+	<tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td></tr>
+	<tr><td>disabled</td><td>s</td><td>Set to "2" to indicate special network block use as a P2P persistent group information</td></tr>
+	<tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>PersistentGroupRemoved ( o : path )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>o : path</dt>
+      <dd>D-Bus object path for the persistent group. See \ref dbus_persistent_group.</dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>WpsFailed ( s : name, a{sv} : args )</h3>
+    <p></p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>s : name</dt>
+      <dd>"fail"</dd>
+      <dt>a{sv} : args</dt>
+      <dd>A dictionary with following information:
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+	  <tr><td>msg</td><td>i</td><td></td></tr>
+	  <tr><td>config_error</td><td>n</td><td></td></tr>
+	</table>
+      </dd>
+    </dl>
+  </li>
+</ul>
+
 \section dbus_bss fi.w1.wpa_supplicant1.BSS
 
 Interface implemented by objects representing a scanned BSSs, i.e.,
@@ -925,6 +1529,13 @@
 	</table>
       </li>
       <li>
+	<h3>WPS - a{sv} - (read)</h3>
+	<p>WPS information of the BSS. Empty dictionary indicates no WPS support. Dictionary entries are:</p>
+	<table>
+	  <tr><td>Type</td><td>s</td><td>"pbc", "pin", ""</td>
+	</table>
+      </li>
+      <li>
 	<h3>IEs - ay - (read)</h3>
 	<p>All IEs of the BSS as a chain of TLVs</p>
       </li>
@@ -948,6 +1559,10 @@
 	<h3>Signal - n - (read)</h3>
 	<p>Signal strength of the BSS.</p>
       </li>
+      <li>
+	<h3>Age - u - (read)</h3>
+	<p>Number of seconds since the BSS was last seen.</p>
+      </li>
     </ul>
 
 \subsection dbus_bss_signals Signals
@@ -979,8 +1594,8 @@
       </li>
 
       <li>
-	<h3>Properties - a{sv} - (read)</h3>
-	<p>Properties of the configured network. Dictionary contains entries from "network" block of %wpa_supplicant configuration file. All values are string type, e.g., frequency is "2437", not 2437.
+	<h3>Properties - a{sv} - (read/write)</h3>
+	<p>Properties of the configured network. Dictionary contains entries from "network" block of wpa_supplicant configuration file. All values are string type, e.g., frequency is "2437", not 2437.
       </li>
     </ul>
 
@@ -998,4 +1613,179 @@
       </li>
     </ul>
 
+\section dbus_peer fi.w1.wpa_supplicant1.Peer
+
+Interface implemented by objects representing P2P peer devices.
+
+\subsection dbus_peer_properties Properties
+
+<ul>
+  <li>
+    <h3>DeviceName - s - (read)</h3>
+  </li>
+
+  <li>
+    <h3>PrimaryDeviceType - ay - (read)</h3>
+  </li>
+
+  <li>
+    <h3>config_method - q - (read)</h3>
+  </li>
+
+  <li>
+    <h3>level - i - (read)</h3>
+  </li>
+
+  <li>
+    <h3>devicecapability - y - (read)</h3>
+  </li>
+
+  <li>
+    <h3>groupcapability - y - (read)</h3>
+    <p>Group Capability field from the last frame from which this peer information was updated.
+    \note This field is only for debugging purposes and must not be used to determine whether the peer happens to be operating a group as a GO at the moment.
+    </p>
+  </li>
+
+  <li>
+    <h3>SecondaryDeviceTypes - aay - (read)</h3>
+  </li>
+
+  <li>
+    <h3>VendorExtension - aay - (read)</h3>
+  </li>
+
+  <li>
+    <h3>IEs - ay - (read)</h3>
+    <p>This is a confusingly named property that includes Wi-Fi Display subelements from the peer.
+    \bug This should really be renamed since "IEs" means something completely different..
+    </p>
+  </li>
+
+  <li>
+    <h3>DeviceAddress - ay - (read)</h3>
+    <p>The P2P Device Address of the peer.</p>
+  </li>
+
+  <li>
+    <h3>Groups - ao - (read)</h3>
+    <p>The current groups in which this peer is connected.</p>
+  </li>
+</ul>
+
+\subsection dbus_peer_signals Signals
+
+<ul>
+  <li>
+    <h3>PropertiesChanged ( a{sv} : properties )</h3>
+    <p>Some properties have changed.
+    \deprecated Use org.freedesktop.DBus.Properties.PropertiesChanged instead.</p>
+    \todo Explain how ProertiesChanged signals are supposed to be of any real use with Peer objects (i.e., one signal for multiple peers).
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and their new values.</dd>
+	</dl>
+      </li>
+    </ul>
+
+\section dbus_group fi.w1.wpa_supplicant1.Group
+
+Interface implemented by objects representing active P2P groups.
+
+\subsection dbus_group_properties Properties
+
+<ul>
+  <li>
+    <h3>Members - ao - (read)</h3>
+    <p>Array of D-Bus object paths for the peer devices that are currently connected to the group. This is valid only on the GO device. An empty array is returned in P2P Client role.
+  </li>
+
+  <li>
+    <h3>Group - o - (read)</h3>
+    <p>\todo Why is this here? This D-Bus object path is to this specific group and one needs to know it to fetching this information in the first place..
+    </p>
+  </li>
+
+  <li>
+    <h3>Role - s - (read)</h3>
+    <p>The role of this device in the group: "GO", "client".</p>
+  </li>
+
+  <li>
+    <h3>SSID - ay - (read)</h3>
+    <p>P2P Group SSID.</p>
+  </li>
+
+  <li>
+    <h3>BSSID - ay - (read)</h3>
+    <p>P2P Group BSSID (the P2P Interface Address of the GO).</p>
+  </li>
+
+  <li>
+    <h3>Frequency - q - (read)</h3>
+    <p>The frequency (in MHz) of the group operating channel.</p>
+  </li>
+
+  <li>
+    <h3>Passphrase - s - (read)</h3>
+    <p>Passphrase used in the group. This is always available on the GO. For P2P Client role, this may be available depending on whether the peer GO provided the passphrase during the WPS provisioning step. If not available, an empty string is returned.</p>
+  </li>
+
+  <li>
+    <h3>PSK - ay - (read)</h3>
+    <p>PSK used in the group.</p>
+  </li>
+
+  <li>
+    <h3>WPSVendorExtensions - aay - (read/write)</h3>
+    <p>WPS vendor extension attributes used on the GO. This is valid only the in the GO role. An empty array is returned in P2P Client role. At maximum, 10 separate vendor extension byte arrays can be configured. The GO device will include the configured attributes in WPS exchanges.</p>
+  </li>
+</ul>
+
+\subsection dbus_group_signals Signals
+
+<ul>
+  <li>
+    <h3>PeerJoined ( o : peer )</h3>
+    <p>A peer device has joined the group. This is indicated only on the GO device.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>o : peer</dt>
+      <dd>A D-Bus path to the object representing the peer. See \ref dbus_peer.</dd>
+    </dl>
+  </li>
+
+  <li>
+    <h3>PeerDisconnected ( o : peer )</h3>
+    <p>A peer device has left the group. This is indicated only on the GO device.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>o : peer</dt>
+      <dd>A D-Bus path to the object representing the peer. See \ref dbus_peer.</dd>
+    </dl>
+  </li>
+</ul>
+
+\section dbus_persistent_group fi.w1.wpa_supplicant1.PersistentGroup
+
+Interface implemented by objects representing persistent P2P groups.
+
+\subsection dbus_persistent_group_properties Properties
+
+<ul>
+  <li>
+    <h3>Properties - a{sv} - (read/write)</h3>
+    <p>Properties of the persistent group. These are same properties as in the \ref dbus_network. When writing this, only the entries to be modified are included, i.e., any item that is not included will be left at its existing value. The following entries are used for persistent groups:</p>
+    <table>
+      <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+      <tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td></tr>
+      <tr><td>ssid</td><td>s</td><td>SSID of the group</td></tr>
+      <tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td></tr>
+      <tr><td>disabled</td><td>s</td><td>Set to "2" to indicate special network block use as a P2P persistent group information</td></tr>
+      <tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td></tr>
+    </table>
+  </li>
+</ul>
+
 */
diff --git a/doc/directories.doxygen b/doc/directories.doxygen
index 7465afe..15e5bda 100644
--- a/doc/directories.doxygen
+++ b/doc/directories.doxygen
@@ -82,9 +82,9 @@
 functionality needed to implement Wi-Fi Protected Setup.
 
 
-\dir wpa_supplicant %wpa_supplicant
+\dir wpa_supplicant wpa_supplicant
 
-%wpa_supplicant-specific code for configuration, control interface, and
+wpa_supplicant-specific code for configuration, control interface, and
 client management.
 
 */
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
index b8c40e3..06be6a5 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf
@@ -31,7 +31,7 @@
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = 2.0
+PROJECT_NUMBER         = 2.4
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
@@ -572,6 +572,8 @@
 	doc \
 	hostapd \
 	wpa_supplicant \
+	wpa_supplicant/dbus \
+	eap_example \
 	src/ap \
 	src/common \
 	src/crypto \
@@ -583,6 +585,7 @@
 	src/eap_server \
 	src/l2_packet \
 	src/p2p \
+	src/pae \
 	src/radius \
 	src/rsn_supp \
 	src/tls \
@@ -1533,3 +1536,12 @@
 # the various graphs.
 
 DOT_CLEANUP            = YES
+
+
+#---------------------------------------------------------------------------
+# Project additions
+#---------------------------------------------------------------------------
+
+# Disable autolink support due to wpa_supplicant getting unfortunately
+# auto-linked to struct wpa_supplicant due to having an underscore in the name.
+AUTOLINK_SUPPORT = FALSE
diff --git a/doc/driver_wrapper.doxygen b/doc/driver_wrapper.doxygen
index 28aea50..a3b470a 100644
--- a/doc/driver_wrapper.doxygen
+++ b/doc/driver_wrapper.doxygen
@@ -3,7 +3,7 @@
 
 All hardware and driver dependent functionality is in separate C files
 that implement defined wrapper functions. Other parts
-of the %wpa_supplicant are designed to be hardware, driver, and operating
+of the wpa_supplicant are designed to be hardware, driver, and operating
 system independent.
 
 Driver wrappers need to implement whatever calls are used in the
@@ -13,45 +13,45 @@
 Extensions (WE). Since features required for WPA were added only recently to
 Linux Wireless Extensions (in version 18), some driver specific code is used
 in number of driver interface implementations. These driver dependent parts
-can be replaced with generic code in driver_wext.c once the target driver
+can be replaced with generic code in \ref driver_wext.c once the target driver
 includes full support for WE-18. After that, all Linux drivers, at
 least in theory, could use the same driver wrapper code.
 
 A driver wrapper needs to implement some or all of the functions
-defined in driver.h. These functions are registered by filling struct
-wpa_driver_ops with function pointers. Hardware independent parts of
-%wpa_supplicant will call these functions to control the driver/wlan
+defined in \ref driver.h. These functions are registered by filling struct
+\ref wpa_driver_ops with function pointers. Hardware independent parts of
+wpa_supplicant will call these functions to control the driver/wlan
 card. In addition, support for driver events is required. The event
-callback function, wpa_supplicant_event(), and its parameters are
-documented in driver.h. In addition, a pointer to the 'struct
-wpa_driver_ops' needs to be registered in drivers.c file.
+callback function, \ref wpa_supplicant_event(), and its parameters are
+documented in \ref driver.h. In addition, a pointer to the 'struct
+\ref wpa_driver_ops' needs to be registered in \ref drivers.c file.
 
 When porting to other operating systems, the driver wrapper should be
 modified to use the native interface of the target OS. It is possible
 that some extra requirements for the interface between the driver
-wrapper and generic %wpa_supplicant code are discovered during porting
+wrapper and generic wpa_supplicant code are discovered during porting
 to a new operating system. These will be addressed on case by case
 basis by modifying the interface and updating the other driver
 wrappers for this. The goal is to avoid changing this interface
 without very good reasons in order to limit the number of changes
 needed to other wrappers and hardware independent parts of
-%wpa_supplicant. When changes are required, recommended way is to
+wpa_supplicant. When changes are required, recommended way is to
 make them in backwards compatible way that allows existing driver
 interface implementations to be compiled without any modification.
 
 Generic Linux Wireless Extensions functions are implemented in
-driver_wext.c. All Linux driver wrappers can use these when the kernel
+\ref driver_wext.c. All Linux driver wrappers can use these when the kernel
 driver supports the generic ioctl()s and wireless events. Driver
 specific functions are implemented in separate C files, e.g.,
-driver_hostap.c. These files need to define struct wpa_driver_ops
-entry that will be used in wpa_supplicant.c when calling driver
-functions. struct wpa_driver_ops entries are registered in drivers.c.
+\ref driver_hostap.c. These files need to define struct \ref wpa_driver_ops
+entry that will be used in \ref wpa_supplicant.c when calling driver
+functions. struct \ref wpa_driver_ops entries are registered in \ref drivers.c.
 
 In general, it is likely to be useful to first take a look at couple
 of driver interface examples before starting on implementing a new
-one. driver_hostap.c and driver_wext.c include a complete
-implementation for Linux drivers that use %wpa_supplicant-based control
-of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
+one. \ref driver_hostap.c and \ref driver_wext.c include a complete
+implementation for Linux drivers that use wpa_supplicant-based control
+of WPA IE and roaming. \ref driver_ndis.c (with help from \ref driver_ndis_.c)
 is an example of a complete interface for Windows NDIS interface for
 drivers that generate WPA IE themselves and decide when to roam. These
 example implementations include full support for all security modes.
@@ -61,7 +61,7 @@
 
 WPA introduces new requirements for the device driver. At least some
 of these need to be implemented in order to provide enough support for
-%wpa_supplicant.
+wpa_supplicant.
 
 \subsection driver_tkip_ccmp TKIP/CCMP
 
@@ -86,12 +86,12 @@
 
 \subsection driver_roaming Roaming control and scanning support
 
-%wpa_supplicant can optionally control AP selection based on the
+wpa_supplicant can optionally control AP selection based on the
 information received from Beacon and/or Probe Response frames
 (ap_scan=1 mode in configuration). This means that the driver should
 support external control for scan process. In case of Linux, use of
 new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is
-recommended. The current driver wrapper (driver_wext.c) uses this for
+recommended. The current driver wrapper (\ref driver_wext.c) uses this for
 scan results.
 
 Scan results must also include the WPA information element. Support for
@@ -99,9 +99,9 @@
 to provide the full WPA IE (including element id and length) as a hex
 string that is included in the scan results.
 
-%wpa_supplicant needs to also be able to request the driver to
+wpa_supplicant needs to also be able to request the driver to
 associate with a specific BSS. Current Host AP driver and matching
-driver_hostap.c wrapper uses following sequence for this
+\ref driver_hostap.c wrapper uses following sequence for this
 request. Similar/identical mechanism should be usable also with other
 drivers.
 
@@ -113,28 +113,28 @@
 
 \subsection driver_wpa_ie WPA IE generation
 
-%wpa_supplicant selects which cipher suites and key management suites
+wpa_supplicant selects which cipher suites and key management suites
 are used. Based on this information, it generates a WPA IE. This is
 provided to the driver interface in the associate call. This does not
 match with Windows NDIS drivers which generate the WPA IE
 themselves.
 
-%wpa_supplicant allows Windows NDIS-like behavior by providing the
+wpa_supplicant allows Windows NDIS-like behavior by providing the
 selected cipher and key management suites in the associate call. If
 the driver generates its own WPA IE and that differs from the one
-generated by %wpa_supplicant, the driver has to inform %wpa_supplicant
+generated by wpa_supplicant, the driver has to inform wpa_supplicant
 about the used WPA IE (i.e., the one it used in (Re)Associate
 Request). This notification is done using EVENT_ASSOCINFO event (see
-driver.h). %wpa_supplicant is normally configured to use
+\ref driver.h). wpa_supplicant is normally configured to use
 ap_scan=2 mode with drivers that control WPA IE generation and roaming.
 
 \subsection driver_events Driver events
 
-%wpa_supplicant needs to receive event callbacks when certain events
+wpa_supplicant needs to receive event callbacks when certain events
 occur (association, disassociation, Michael MIC failure, scan results
 available, PMKSA caching candidate). These events and the callback
-details are defined in driver.h (wpa_supplicant_event() function
-and enum wpa_event_type).
+details are defined in \ref driver.h (\ref wpa_supplicant_event() function
+and enum \ref wpa_event_type).
 
 On Linux, association and disassociation can use existing Wireless
 Extensions event that is reporting new AP with SIOCGIWAP
@@ -153,18 +153,18 @@
 
 ap_scan=1:
 
-- %wpa_supplicant requests scan with SIOCSIWSCAN
+- wpa_supplicant requests scan with SIOCSIWSCAN
 - driver reports scan complete with wireless event SIOCGIWSCAN
-- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
+- wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
   a larget buffer is needed)
-- %wpa_supplicant decides which AP to use based on scan results
-- %wpa_supplicant configures driver to associate with the selected BSS
+- wpa_supplicant decides which AP to use based on scan results
+- wpa_supplicant configures driver to associate with the selected BSS
   (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
    SIOCSIWESSID, SIOCSIWAP)
 
 ap_scan=2:
 
-- %wpa_supplicant configures driver to associate with an SSID
+- wpa_supplicant configures driver to associate with an SSID
   (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
 
 
@@ -174,7 +174,7 @@
   (Re)AssocReq), driver reports association parameters (AssocReq IEs)
   with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
 - driver reports association with wireless event SIOCGIWAP
-- %wpa_supplicant takes care of EAPOL frame handling (validating
+- wpa_supplicant takes care of EAPOL frame handling (validating
   information from associnfo and if needed, from scan results if WPA/RSN
   IE from the Beacon frame is not reported through associnfo)
 */
diff --git a/doc/eap.doxygen b/doc/eap.doxygen
index 6a24829..fc7ea26 100644
--- a/doc/eap.doxygen
+++ b/doc/eap.doxygen
@@ -2,44 +2,44 @@
 \page eap_peer_module EAP peer implementation
 
 Extensible Authentication Protocol (EAP) is an authentication framework
-defined in RFC 3748. %wpa_supplicant uses a separate code module for EAP
+defined in RFC 3748. wpa_supplicant uses a separate code module for EAP
 peer implementation. This module was designed to use only a minimal set
 of direct function calls (mainly, to debug/event functions) in order for
 it to be usable in other programs. The design of the EAP
 implementation is based loosely on RFC 4137. The state machine is
 defined in this RFC and so is the interface between the peer state
 machine and methods. As such, this RFC provides useful information for
-understanding the EAP peer implementation in %wpa_supplicant.
+understanding the EAP peer implementation in wpa_supplicant.
 
 Some of the terminology used in EAP state machine is referring to
 EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
 layer being IEEE 802.1X if EAP module is built for other programs than
-%wpa_supplicant. These terms should be understood to refer to the
+wpa_supplicant. These terms should be understood to refer to the
 lower layer as defined in RFC 4137.
 
 
 \section adding_eap_methods Adding EAP methods
 
 Each EAP method is implemented as a separate module, usually as one C
-file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+file named eap_<name of the method>.c, e.g., \ref eap_md5.c. All EAP
 methods use the same interface between the peer state machine and
 method specific functions. This allows new EAP methods to be added
 without modifying the core EAP state machine implementation.
 
 New EAP methods need to be registered by adding them into the build
 (Makefile) and the EAP method registration list in the
-eap_peer_register_methods() function of eap_methods.c. Each EAP
+\ref eap_peer_register_methods() function of \ref eap_methods.c. Each EAP
 method should use a build-time configuration option, e.g., EAP_TLS, in
 order to make it possible to select which of the methods are included
 in the build.
 
-EAP methods must implement the interface defined in eap_i.h. struct
+EAP methods must implement the interface defined in \ref eap_i.h. struct
 eap_method defines the needed function pointers that each EAP method
 must provide. In addition, the EAP type and name are registered using
 this structure. This interface is based on section 4.4 of RFC 4137.
 
 It is recommended that the EAP methods would use generic helper
-functions, eap_msg_alloc() and eap_hdr_validate() when processing
+functions, \ref eap_msg_alloc() and \ref eap_hdr_validate() when processing
 messages. This allows code sharing and can avoid missing some of the
 needed validation steps for received packets. In addition, these
 functions make it easier to change between expanded and legacy EAP
@@ -48,23 +48,23 @@
 When adding an EAP method that uses a vendor specific EAP type
 (Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
 must be registered by passing vendor id instead of EAP_VENDOR_IETF to
-eap_peer_method_alloc(). These methods must not try to emulate
+\ref eap_peer_method_alloc(). These methods must not try to emulate
 expanded types by registering a legacy EAP method for type 254. See
-eap_vendor_test.c for an example of an EAP method implementation that
+\ref eap_vendor_test.c for an example of an EAP method implementation that
 is implemented as an expanded type.
 
 
 \section used_eap_library Using EAP implementation as a library
 
 The Git repository has an eap_example directory that contains an
-example showing how EAP peer and server code from %wpa_supplicant and
+example showing how EAP peer and server code from wpa_supplicant and
 hostapd can be used as a library. The example program initializes both
 an EAP server and an EAP peer entities and then runs through an
 EAP-PEAP/MSCHAPv2 authentication.
 
-eap_example_peer.c shows the initialization and glue code needed to
-control the EAP peer implementation. eap_example_server.c does the
-same for EAP server. eap_example.c is an example that ties in both the
+\ref eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. \ref eap_example_server.c does the
+same for EAP server. \ref eap_example.c is an example that ties in both the
 EAP server and client parts to allow an EAP authentication to be
 shown.
 
@@ -77,9 +77,9 @@
 EAP messages and WiMax supports optional PMK EAP authentication
 mechanism that transmits EAP messages as defined in IEEE 802.16e.
 
-The EAP library links in number of helper functions from src/utils and
-src/crypto directories. Most of these are suitable as-is, but it may
-be desirable to replace the debug output code in src/utils/wpa_debug.c
+The EAP library links in number of helper functions from \ref src/utils and
+\ref src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in \ref src/utils/wpa_debug.c
 by dropping this file from the library and re-implementing the
 functions there in a way that better fits in with the main
 application.
diff --git a/doc/eap_server.doxygen b/doc/eap_server.doxygen
index 4aca53d..f60ac79 100644
--- a/doc/eap_server.doxygen
+++ b/doc/eap_server.doxygen
@@ -14,32 +14,32 @@
 Some of the terminology used in EAP state machine is referring to
 EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
 layer being IEEE 802.1X if EAP module is built for other programs than
-%wpa_supplicant. These terms should be understood to refer to the
+wpa_supplicant. These terms should be understood to refer to the
 lower layer as defined in RFC 4137.
 
 
 \section adding_eap_methods Adding EAP methods
 
 Each EAP method is implemented as a separate module, usually as one C
-file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+file named eap_server_<name of the method>.c, e.g., \ref eap_server_md5.c. All EAP
 methods use the same interface between the server state machine and
 method specific functions. This allows new EAP methods to be added
 without modifying the core EAP state machine implementation.
 
 New EAP methods need to be registered by adding them into the build
 (Makefile) and the EAP method registration list in the
-eap_server_register_methods() function of eap_methods.c. Each EAP
+\ref eap_server_register_methods() function of \ref eap_server_methods.c. Each EAP
 method should use a build-time configuration option, e.g., EAP_TLS, in
 order to make it possible to select which of the methods are included
 in the build.
 
-EAP methods must implement the interface defined in eap_i.h. struct
-eap_method defines the needed function pointers that each EAP method
+EAP methods must implement the interface defined in \ref eap_i.h. struct
+\ref eap_method defines the needed function pointers that each EAP method
 must provide. In addition, the EAP type and name are registered using
 this structure. This interface is based on section 4.4 of RFC 4137.
 
 It is recommended that the EAP methods would use generic helper
-functions, eap_msg_alloc() and eap_hdr_validate() when processing
+functions, \ref eap_msg_alloc() and \ref eap_hdr_validate() when processing
 messages. This allows code sharing and can avoid missing some of the
 needed validation steps for received packets. In addition, these
 functions make it easier to change between expanded and legacy EAP
@@ -48,9 +48,9 @@
 When adding an EAP method that uses a vendor specific EAP type
 (Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
 must be registered by passing vendor id instead of EAP_VENDOR_IETF to
-eap_server_method_alloc(). These methods must not try to emulate
+\ref eap_server_method_alloc(). These methods must not try to emulate
 expanded types by registering a legacy EAP method for type 254. See
-eap_vendor_test.c for an example of an EAP method implementation that
+\ref eap_server_vendor_test.c for an example of an EAP method implementation that
 is implemented as an expanded type.
 
 */
diff --git a/doc/hostapd_ctrl_iface.doxygen b/doc/hostapd_ctrl_iface.doxygen
index ae778bc..4d2bac8 100644
--- a/doc/hostapd_ctrl_iface.doxygen
+++ b/doc/hostapd_ctrl_iface.doxygen
@@ -4,58 +4,58 @@
 hostapd implements a control interface that can be used by
 external programs to control the operations of the hostapd
 daemon and to get status information and event notifications. There is
-a small C library, in a form of a single C file, wpa_ctrl.c, that
+a small C library, in a form of a single C file, \ref wpa_ctrl.c, that
 provides helper functions to facilitate the use of the control
 interface. External programs can link this file into them and then use
-the library functions documented in wpa_ctrl.h to interact with
-%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+the library functions documented in \ref wpa_ctrl.h to interact with
+wpa_supplicant. This library can also be used with C++. \ref hostapd_cli.c
 is an example program using this library.
 
 There are multiple mechanisms for inter-process communication. For
 example, Linux version of hostapd is using UNIX domain sockets for the
-control interface. The use of the functions defined in wpa_ctrl.h can
+control interface. The use of the functions defined in \ref wpa_ctrl.h can
 be used to hide the details of the used IPC from external programs.
 
 
 \section using_ctrl_iface Using the control interface
 
 External programs, e.g., a GUI or a configuration utility, that need to
-communicate with hostapd should link in wpa_ctrl.c. This
+communicate with hostapd should link in \ref wpa_ctrl.c. This
 allows them to use helper functions to open connection to the control
-interface with wpa_ctrl_open() and to send commands with
-wpa_ctrl_request().
+interface with \ref wpa_ctrl_open() and to send commands with
+\ref wpa_ctrl_request().
 
 hostapd uses the control interface for two types of communication:
 commands and unsolicited event messages. Commands are a pair of
 messages, a request from the external program and a response from
-hostapd. These can be executed using wpa_ctrl_request().
+hostapd. These can be executed using \ref wpa_ctrl_request().
 Unsolicited event messages are sent by hostapd to the control
 interface connection without specific request from the external program
 for receiving each message. However, the external program needs to
-attach to the control interface with wpa_ctrl_attach() to receive these
+attach to the control interface with \ref wpa_ctrl_attach() to receive these
 unsolicited messages.
 
 If the control interface connection is used both for commands and
 unsolicited event messages, there is potential for receiving an
 unsolicited message between the command request and response.
-wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+\ref wpa_ctrl_request() caller will need to supply a callback, msg_cb,
 for processing these messages. Often it is easier to open two
-control interface connections by calling wpa_ctrl_open() twice and
+control interface connections by calling \ref wpa_ctrl_open() twice and
 then use one of the connections for commands and the other one for
 unsolicited messages. This way command request/response pairs will
-not be broken by unsolicited messages. wpa_cli is an example of how
+not be broken by unsolicited messages. \ref wpa_cli.c is an example of how
 to use only one connection for both purposes and wpa_gui demonstrates
 how to use two separate connections.
 
 Once the control interface connection is not needed anymore, it should
-be closed by calling wpa_ctrl_close(). If the connection was used for
+be closed by calling \ref wpa_ctrl_close(). If the connection was used for
 unsolicited event messages, it should be first detached by calling
-wpa_ctrl_detach().
+\ref wpa_ctrl_detach().
 
 
 \section ctrl_iface_cmds Control interface commands
 
-Following commands can be used with wpa_ctrl_request():
+Following commands can be used with \ref wpa_ctrl_request():
 
 \subsection ctrl_iface_PING PING
 
diff --git a/doc/mainpage.doxygen b/doc/mainpage.doxygen
index 26dc929..329afea 100644
--- a/doc/mainpage.doxygen
+++ b/doc/mainpage.doxygen
@@ -3,17 +3,17 @@
 
 The goal of this documentation and comments in the source code is to
 give enough information for other developers to understand how
-%wpa_supplicant and hostapd have been implemented, how they can be
+wpa_supplicant and hostapd have been implemented, how they can be
 modified, how new drivers can be supported, and how the source code
 can be ported to other operating systems. If any information is
 missing, feel free to contact Jouni Malinen <j@w1.fi> for more
 information. Contributions as patch files are also very welcome at the
 same address. Please note that this software is licensed under the
 BSD license (the one with advertisement clause removed). All
-contributions to %wpa_supplicant and hostapd are expected to use
+contributions to wpa_supplicant and hostapd are expected to use
 compatible licensing terms.
 
-The source code and read-only access to the combined %wpa_supplicant
+The source code and read-only access to the combined wpa_supplicant
 and hostapd Git repository is available from the project home page at
 http://w1.fi/wpa_supplicant/. This developers' documentation is also
 available as a PDF file from
@@ -22,14 +22,14 @@
 
 \section _wpa_supplicant wpa_supplicant
 
-%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
+wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
 support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
 802.1X/WPA component that is used in the client stations. It
 implements key negotiation with a WPA Authenticator and it can optionally
 control roaming and IEEE 802.11 authentication/association of the wlan
 driver.
 
-The design goal for %wpa_supplicant was to use hardware, driver, and
+The design goal for wpa_supplicant was to use hardware, driver, and
 OS independent, portable C code for all WPA functionality. The source
 code is divided into separate C files as shown on the \ref
 code_structure "code structure page". All hardware/driver specific
@@ -41,15 +41,15 @@
 EAPOL (IEEE 802.1X) state machines are implemented as a separate
 module that interacts with \ref eap_peer_module "EAP peer implementation".
 In addition to programs aimed at normal production use,
-%wpa_supplicant source tree includes number of \ref testing_tools
+wpa_supplicant source tree includes number of \ref testing_tools
 "testing and development tools" that make it easier to test the
 programs without having to setup a full test setup with wireless
 cards. These tools can also be used to implement automatic test
 suites.
 
-%wpa_supplicant implements a
+wpa_supplicant implements a
 \ref ctrl_iface_page "control interface" that can be used by
-external programs to control the operations of the %wpa_supplicant
+external programs to control the operations of the wpa_supplicant
 daemon and to get status information and event notifications. There is
 a small C library that provides helper functions to facilitate the use of the
 control interface. This library can also be used with C++.
diff --git a/doc/p2p.doxygen b/doc/p2p.doxygen
index 27656eb..c1a81db 100644
--- a/doc/p2p.doxygen
+++ b/doc/p2p.doxygen
@@ -3,7 +3,7 @@
 
 Wi-Fi Direct functionality is implemented any many levels in the WLAN
 stack from low-level driver operations to high-level GUI design. This
-document covers the parts that can be user by %wpa_supplicant. However,
+document covers the parts that can be user by wpa_supplicant. However,
 it should be noted that alternative designs are also possible, so some
 of the functionality may reside in other components in the system.
 
@@ -19,16 +19,16 @@
 groups. It takes care of Device Discovery, Service Discovery, Group
 Owner Negotiation, P2P Invitation. In addition, it maintains
 information about neighboring P2P Devices. This module could be used
-in designs that do not use %wpa_supplicant and it could also reside
+in designs that do not use wpa_supplicant and it could also reside
 inside the driver/firmware component. P2P module API is defined in
-src/p2p/p2p.h.
+\ref src/p2p/p2p.h.
 
 Provisioning step of Group Formation is implemented using WPS
-(src/wps/wps.h).
+(\ref src/wps/wps.h).
 
-%wpa_supplicant includes code in interact with both the P2P module
-(wpa_supplicant/p2p_supplicant.c) and WPS
-(wpa_supplicant/wps_supplicant.c). The driver operations are passed
+wpa_supplicant includes code in interact with both the P2P module
+(\ref wpa_supplicant/p2p_supplicant.c) and WPS
+(\ref wpa_supplicant/wps_supplicant.c). The driver operations are passed
 through these files, i.e., core P2P or WPS code does not interact
 directly with the driver interface.
 
@@ -48,7 +48,7 @@
 \subsection p2p_arch_mac80211 P2P architecture with Linux/mac80211/ath9k
 
 An architecture where the P2P module resides inside the
-%wpa_supplicant process is used with Linux mac80211-based drivers,
+wpa_supplicant process is used with Linux mac80211-based drivers,
 e.g., ath9k. The following diagram shows the main components related
 to P2P functionality in such an architecture.
 
@@ -82,7 +82,7 @@
 
 \subsection p2p_module_api P2P module API
 
-P2P module API is defined in src/p2p/p2p.h. The API consists of
+P2P module API is defined in \ref src/p2p/p2p.h. The API consists of
 functions for requesting operations and for providing event
 notifications. Similar set of callback functions are configured with
 struct p2p_config to provide callback functions that P2P module can
@@ -92,51 +92,51 @@
 
 These are the main functions for an upper layer management entity to
 request P2P operations:
-- p2p_find()
-- p2p_stop_find()
-- p2p_listen()
-- p2p_connect()
-- p2p_reject()
-- p2p_prov_disc_req()
-- p2p_sd_request()
-- p2p_sd_cancel_request()
-- p2p_sd_response()
-- p2p_sd_service_update()
-- p2p_invite()
+- \ref p2p_find()
+- \ref p2p_stop_find()
+- \ref p2p_listen()
+- \ref p2p_connect()
+- \ref p2p_reject()
+- \ref p2p_prov_disc_req()
+- \ref p2p_sd_request()
+- \ref p2p_sd_cancel_request()
+- \ref p2p_sd_response()
+- \ref p2p_sd_service_update()
+- \ref p2p_invite()
 
 These are the main callback functions for P2P module to provide event
 notifications to the upper layer management entity:
 
-- p2p_config::dev_found()
-- p2p_config::go_neg_req_rx()
-- p2p_config::go_neg_completed()
-- p2p_config::sd_request()
-- p2p_config::sd_response()
-- p2p_config::prov_disc_req()
-- p2p_config::prov_disc_resp()
-- p2p_config::invitation_process()
-- p2p_config::invitation_received()
-- p2p_config::invitation_result()
+- \ref p2p_config::dev_found()
+- \ref p2p_config::go_neg_req_rx()
+- \ref p2p_config::go_neg_completed()
+- \ref p2p_config::sd_request()
+- \ref p2p_config::sd_response()
+- \ref p2p_config::prov_disc_req()
+- \ref p2p_config::prov_disc_resp()
+- \ref p2p_config::invitation_process()
+- \ref p2p_config::invitation_received()
+- \ref p2p_config::invitation_result()
 
 The P2P module uses following functions to request lower layer driver
 operations:
 
-- p2p_config::p2p_scan()
-- p2p_config::send_probe_resp()
-- p2p_config::send_action()
-- p2p_config::send_action_done()
-- p2p_config::start_listen()
-- p2p_config::stop_listen()
+- \ref p2p_config::p2p_scan()
+- \ref p2p_config::send_probe_resp()
+- \ref p2p_config::send_action()
+- \ref p2p_config::send_action_done()
+- \ref p2p_config::start_listen()
+- \ref p2p_config::stop_listen()
 
 Events from lower layer driver operations are delivered to the P2P
 module with following functions:
 
-- p2p_probe_req_rx()
-- p2p_rx_action()
-- p2p_scan_res_handler()
-- p2p_scan_res_handled()
-- p2p_send_action_cb()
-- p2p_listen_cb()
+- \ref p2p_probe_req_rx()
+- \ref p2p_rx_action()
+- \ref p2p_scan_res_handler()
+- \ref p2p_scan_res_handled()
+- \ref p2p_send_action_cb()
+- \ref p2p_listen_cb()
 
 In addition to the per-device state, the P2P module maintains
 per-group state for group owners. This is initialized with a call to
@@ -144,39 +144,36 @@
 p2p_group_deinit(). The upper layer GO management entity uses
 following functions to interact with the P2P per-group state:
 
-- p2p_group_notif_assoc()
-- p2p_group_notif_disassoc()
-- p2p_group_notif_formation_done()
-- p2p_group_match_dev_type()
+- \ref p2p_group_notif_assoc()
+- \ref p2p_group_notif_disassoc()
+- \ref p2p_group_notif_formation_done()
+- \ref p2p_group_match_dev_type()
 
 The P2P module will use following callback function to update P2P IE
 for GO Beacon and Probe Response frames:
 
-- p2p_group_config::ie_update()
+- \ref p2p_group_config::ie_update()
 
 
 \section p2p_driver P2P driver operations (low-level interface)
 
 The following driver wrapper functions are needed for P2P in addition
 to the standard station/AP mode operations when the P2P module resides
-within %wpa_supplicant:
-- wpa_driver_ops::if_add()
-- wpa_driver_ops::if_remove()
-- wpa_driver_ops::alloc_interface_addr()
-- wpa_driver_ops::release_interface_addr()
-- wpa_driver_ops::remain_on_channel()
-- wpa_driver_ops::cancel_remain_on_channel()
-- wpa_driver_ops::send_action()
-- wpa_driver_ops::probe_req_report()
-- wpa_driver_ops::disable_11b_rates()
+within wpa_supplicant:
+- \ref wpa_driver_ops::if_add()
+- \ref wpa_driver_ops::if_remove()
+- \ref wpa_driver_ops::remain_on_channel()
+- \ref wpa_driver_ops::cancel_remain_on_channel()
+- \ref wpa_driver_ops::send_action()
+- \ref wpa_driver_ops::probe_req_report()
 
 The following driver wrapper events are needed for P2P in addition to
 the standard station/AP mode events when the P2P module resides within
-%wpa_supplicant:
-- wpa_event_type::EVENT_RX_ACTION
-- wpa_event_type::EVENT_REMAIN_ON_CHANNEL
-- wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
-- wpa_event_type::EVENT_RX_PROBE_REQ
+wpa_supplicant:
+- \ref wpa_event_type::EVENT_RX_MGMT
+- \ref wpa_event_type::EVENT_REMAIN_ON_CHANNEL
+- \ref wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
+- \ref wpa_event_type::EVENT_RX_PROBE_REQ
 
 
 \section p2p_go_neg P2P device discovery and group formation
@@ -188,40 +185,40 @@
 in the system.
 
 An upper layer management entity starts P2P device discovery by
-calling p2p_find(). The P2P module start the discovery by requesting a
-full scan to be completed by calling p2p_config::p2p_scan(). Results
-from the scan will be reported by calling p2p_scan_res_handler() and
+calling \ref p2p_find(). The P2P module start the discovery by requesting a
+full scan to be completed by calling \ref p2p_config::p2p_scan(). Results
+from the scan will be reported by calling \ref p2p_scan_res_handler() and
 after last result, the scan result processing is terminated with a
-call to p2p_scan_res_handled(). The P2P peers that are found during
-the full scan are reported with the p2p_config::dev_found() callback.
+call to \ref p2p_scan_res_handled(). The P2P peers that are found during
+the full scan are reported with the \ref p2p_config::dev_found() callback.
 
 After the full scan, P2P module start alternating between Listen and
 Search states until the device discovery operation times out or
-terminated, e.g., with a call to p2p_stop_find().
+terminated, e.g., with a call to \ref p2p_stop_find().
 
 When going into the Listen state, the P2P module requests the driver
 to be configured to be awake on the listen channel with a call to
-p2p_config::start_listen(). The glue code using the P2P module may
+\ref p2p_config::start_listen(). The glue code using the P2P module may
 implement this, e.g., by using remain-on-channel low-level driver
 functionality for off-channel operation. Once the driver is available
 on the requested channel, notification of this is delivered by calling
-p2p_listen_cb(). The Probe Request frames that are received during the
+\ref p2p_listen_cb(). The Probe Request frames that are received during the
 Listen period are delivered to the P2P module by calling
-p2p_config::p2p_probe_req_rx() and P2P module request a response to
-these to be sent by using p2p_config::send_probe_resp() callback
+\ref p2p_config::p2p_probe_req_rx() and P2P module request a response to
+these to be sent by using \ref p2p_config::send_probe_resp() callback
 function. If a group owner negotiation from another P2P device is
 received during the device discovery phase, that is indicated to the
-upper layer code with the p2p_config::go_neg_req_tx() callback.
+upper layer code with the \ref p2p_config::go_neg_req_tx() callback.
 
 The Search state is implemented by using the normal scan interface,
-i.e., the P2P module will call p2p_config::p2p_scan() just like in the
+i.e., the P2P module will call \ref p2p_config::p2p_scan() just like in the
 full scan phase described. Similarly, scan results from the search
 operation will be delivered to the P2P module using the
-p2p_scan_res_handler() and p2p_scan_res_handled() functions.
+\ref p2p_scan_res_handler() and \ref p2p_scan_res_handled() functions.
 
 Once the upper layer management entity has found a peer with which it
 wants to connect by forming a new group, it initiates group owner
-negotiation by calling p2p_connect(). Before doing this, the upper
+negotiation by calling \ref p2p_connect(). Before doing this, the upper
 layer code is responsible for asking the user to provide the PIN to be
 used during the provisioning step with the peer or the push button
 press for PBC mode. The glue code will need to figure out the intended
@@ -231,25 +228,25 @@
 Optional Provision Discovery mechanism can be used to request the peer
 to display a PIN for the local device to enter (and vice versa). Upper
 layer management entity can request the specific mechanism by calling
-p2p_prov_disc_req(). The response to this will be reported with the
-p2p_config::prov_disc_resp() callback. If the peer device started
+\ref p2p_prov_disc_req(). The response to this will be reported with the
+\ref p2p_config::prov_disc_resp() callback. If the peer device started
 Provision Discovery, an accepted request will be reported with the
-p2p_config::prov_disc_req() callback. The P2P module will
+\ref p2p_config::prov_disc_req() callback. The P2P module will
 automatically accept the Provision Discovery for display and keypad
 methods, but it is up to the upper layer manegement entity to actually
-generate the PIN and to configure it with following p2p_connect() call
+generate the PIN and to configure it with following \ref p2p_connect() call
 to actually authorize the connection.
 
-The P2P module will use p2p_config::send_action() callback to request
+The P2P module will use \ref p2p_config::send_action() callback to request
 lower layer code to transmit an Action frame during group owner
-negotiation. p2p_send_action_cb() is used to report the result of
+negotiation. \ref p2p_send_action_cb() is used to report the result of
 transmission. If the peer is not reachable, the P2P module will try to
 find it by alternating between Action frame send and Listen
 states. The Listen state for this phase will be used similarly to the
 Listen state during device discovery as described above.
 
 Once the group owner negotiation has been completed, its results will
-be reported with the p2p_config::go_neg_completed() callback. The
+be reported with the \ref p2p_config::go_neg_completed() callback. The
 upper layer management code or the glue code using the P2P module API
 is responsible for creating a new group interface and starting
 provisioning step at this point by configuring WPS Registrar or
@@ -258,15 +255,15 @@
 provisioning if it cannot be completed in 15 seconds.
 
 Successful completion of the WPS provisioning is reported with a call
-to p2p_wps_success_cb(). The P2P module will clear its group formation
+to \ref p2p_wps_success_cb(). The P2P module will clear its group formation
 state at this point and allows new group formation attempts to be
 started. The upper layer management code is responsible for configuring
 the GO to accept associations from devices and the client to connect to
 the GO with the provisioned credentials. GO is also responsible for
-calling p2p_group_notif_formation_done() as described below.
+calling \ref p2p_group_notif_formation_done() as described below.
 
 If the WPS provisioning step fails or times out, this is reported with
-a call to p2p_group_formation_failed(). The P2P module will clear its
+a call to \ref p2p_group_formation_failed(). The P2P module will clear its
 group formation state at this point and allows new group formation
 attempts to be started. The upper layer management code is responsible
 for removing the group interface for the failed group.
@@ -289,23 +286,23 @@
 \subsection p2p_sd_query Quering services of peers
 
 Service discovery is implemented by processing pending queries as a
-part of the device discovery phase. p2p_sd_request() function is used
+part of the device discovery phase. \ref p2p_sd_request() function is used
 to schedule service discovery queries to a specific peer or to all
-discovered peers. p2p_sd_cancel_request() can be used to cancel a
+discovered peers. \ref p2p_sd_cancel_request() can be used to cancel a
 scheduled query. Queries that are specific to a single peer will be
 removed automatically after the response has been received.
 
 After the service discovery queries have been queued, device discovery
-is started with a call to p2p_find(). The pending service discovery
+is started with a call to \ref p2p_find(). The pending service discovery
 queries are then sent whenever a peer is discovered during the find
 operation. Responses to the queries will be reported with the
-p2p_config::sd_response() callback.
+\ref p2p_config::sd_response() callback.
 
 \subsection p2p_sd_response Replying to service discovery queries from peers
 
 The received service discovery requests will be indicated with the
-p2p_config::sd_request() callback. The response to the query is sent
-by calling p2p_sd_response().
+\ref p2p_config::sd_request() callback. The response to the query is sent
+by calling \ref p2p_sd_response().
 
 \subsection p2p_sd_indicator Service update indicator
 
@@ -314,9 +311,9 @@
 Update Indicator value whenever there is a change in the
 services. This value is included in all SD request and response
 frames. The value received from the peers will be included in the
-p2p_config::sd_request() and p2p_config::sd_response() callbacks. The
+\ref p2p_config::sd_request() and \ref p2p_config::sd_response() callbacks. The
 value to be sent to the peers is incremented with a call to
-p2p_sd_service_update() whenever availibility of the local services
+\ref p2p_sd_service_update() whenever availibility of the local services
 changes.
 
 
@@ -329,29 +326,29 @@
 system.
 
 When a P2P group interface is created in group owner role, per-group
-data is initialized with p2p_group_init(). This call provides a
+data is initialized with \ref p2p_group_init(). This call provides a
 pointer to the per-device P2P module context and configures the
-per-group operation. The configured p2p_group_config::ie_update()
+per-group operation. The configured \ref p2p_group_config::ie_update()
 callback is used to set the initial P2P IE for Beacon and Probe
 Response frames in the group owner. The AP mode implementation may use
 this information to add IEs into the frames.
 
 Once the group formation has been completed (or if it is skipped in
-case of manual group setup), p2p_group_notif_formation_done() is
+case of manual group setup), \ref p2p_group_notif_formation_done() is
 called. This will allow the P2P module to update the P2P IE for
 Beacon and Probe Response frames.
 
 The SME/MLME code that managements IEEE 802.11 association processing
 needs to inform P2P module whenever a P2P client associates or
 disassociates with the group. This is done by calling
-p2p_group_notif_assoc() and p2p_group_notif_disassoc(). The P2P module
+\ref p2p_group_notif_assoc() and \ref p2p_group_notif_disassoc(). The P2P module
 manages a list of group members and updates the P2P Group Information
 subelement in the P2P IE based on the information from the P2P
-clients. The p2p_group_config::ie_update() callback is used whenever
+clients. The \ref p2p_group_config::ie_update() callback is used whenever
 the P2P IE in Probe Response frames needs to be changed.
 
 The SME/MLME code that takes care of replying to Probe Request frames
-can use p2p_group_match_dev_type() to check whether the Probe Request
+can use \ref p2p_group_match_dev_type() to check whether the Probe Request
 frame request a reply only from groups that include a specific device
 type in one of the clients or GO. A match will be reported if the
 Probe Request does not request a specific device type, so this
@@ -359,13 +356,13 @@
 only the ones that result in non-zero return value need to be replied.
 
 When the P2P group interface for GO role is removed,
-p2p_group_deinit() is used to deinitialize the per-group P2P module
+\ref p2p_group_deinit() is used to deinitialize the per-group P2P module
 state.
 
 
 \section p2p_ctrl_iface P2P control interface
 
-%wpa_supplicant \ref ctrl_iface_page "control interface" can be used
+wpa_supplicant \ref ctrl_iface_page "control interface" can be used
 to manage P2P functionality from an external program (e.g., a GUI or a
 system configuration manager). This interface can be used directly
 through the control interface backend mechanism (e.g., local domain
@@ -414,11 +411,11 @@
 
 \subsection p2p_wpa_cli wpa_cli example
 
-wpa_cli can be used to control %wpa_supplicant in interactive
+wpa_cli can be used to control wpa_supplicant in interactive
 mode. The following sessions show examples of commands used for
 device discovery and group formation. The lines starting with "> " are
 commands from the user (followed by command result indication) and
-lines starting with "<2>" are event messages from %wpa_supplicant.
+lines starting with "<2>" are event messages from wpa_supplicant.
 
 P2P device "Wireless Client":
 
diff --git a/doc/porting.doxygen b/doc/porting.doxygen
index 7ea6a34..b4b78ef 100644
--- a/doc/porting.doxygen
+++ b/doc/porting.doxygen
@@ -1,14 +1,14 @@
 /**
 \page porting Porting to different target boards and operating systems
 
-%wpa_supplicant was designed to be easily portable to different
+wpa_supplicant was designed to be easily portable to different
 hardware (board, CPU) and software (OS, drivers) targets. It is
 already used with number of operating systems and numerous wireless
-card models and drivers. The main %wpa_supplicant repository includes
+card models and drivers. The main wpa_supplicant repository includes
 support for Linux, FreeBSD, and Windows. In addition, the code has been
 ported to number of other operating systems like VxWorks, PalmOS,
 Windows CE, and Windows Mobile. On the hardware
-side, %wpa_supplicant is used on various systems: desktops, laptops,
+side, wpa_supplicant is used on various systems: desktops, laptops,
 PDAs, and embedded devices with CPUs including x86, PowerPC,
 arm/xscale, and MIPS. Both big and little endian configurations are
 supported.
@@ -16,48 +16,48 @@
 
 \section ansi_c_extra Extra functions on top of ANSI C
 
-%wpa_supplicant is mostly using ANSI C functions that are available on
+wpa_supplicant is mostly using ANSI C functions that are available on
 most targets. However, couple of additional functions that are common
 on modern UNIX systems are used. Number of these are listed with
-prototypes in common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
+prototypes in \ref common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
 block). These functions may need to be implemented or at least defined
 as macros to native functions in the target OS or C library.
 
 Many of the common ANSI C functions are used through a wrapper
-definitions in os.h to allow these to be replaced easily with a
+definitions in \ref os.h to allow these to be replaced easily with a
 platform specific version in case standard C libraries are not
-available. In addition, os.h defines couple of common platform
-specific functions that are implemented in os_unix.c for UNIX like
-targets and in os_win32.c for Win32 API. If the target platform does
+available. In addition, \ref os.h defines couple of common platform
+specific functions that are implemented in \ref os_unix.c for UNIX like
+targets and in \ref os_win32.c for Win32 API. If the target platform does
 not support either of these examples, a new os_*.c file may need to be
 added.
 
 Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX
 functions are used by defining the os_*() wrappers to use them
 directly in order to avoid extra cost in size and speed. If the target
-platform needs different versions of the functions, os.h can be
+platform needs different versions of the functions, \ref os.h can be
 modified to define the suitable macros or alternatively,
 OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper
 functions can then be implemented in a new os_*.c wrapper file.
 
-common.h defines number of helper macros for handling integers of
+\ref common.h defines number of helper macros for handling integers of
 different size and byte order. Suitable version of these definitions
 may need to be added for the target platform.
 
 
 \section configuration_backend Configuration backend
 
-%wpa_supplicant implements a configuration interface that allows the
+wpa_supplicant implements a configuration interface that allows the
 backend to be easily replaced in order to read configuration data from
-a suitable source depending on the target platform. config.c
+a suitable source depending on the target platform. \ref config.c
 implements the generic code that can be shared with all configuration
 backends. Each backend is implemented in its own config_*.c file.
 
-The included config_file.c backend uses a text file for configuration
-and config_winreg.c uses Windows registry. These files can be used as
+The included \ref config_file.c backend uses a text file for configuration
+and \ref config_winreg.c uses Windows registry. These files can be used as
 an example for a new configuration backend if the target platform uses
 different mechanism for configuration parameters. In addition,
-config_none.c can be used as an empty starting point for building a
+\ref config_none.c can be used as an empty starting point for building a
 new configuration backend.
 
 
@@ -69,19 +69,19 @@
 (driver_*.c) if the new target is similar to one of them. \ref
 driver_wrapper "Driver wrapper implementation" describes the details
 of the driver interface and discusses the tasks involved in porting
-this part of %wpa_supplicant.
+this part of wpa_supplicant.
 
 
 \section l2_packet_porting l2_packet (link layer access)
 
-%wpa_supplicant needs to have access to sending and receiving layer 2
+wpa_supplicant needs to have access to sending and receiving layer 2
 (link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
-and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces
-used for this in the core %wpa_supplicant implementation.
+and RSN pre-authentication 0x88c7. \ref l2_packet.h defines the interfaces
+used for this in the core wpa_supplicant implementation.
 
 If the target operating system supports a generic mechanism for link
 layer access, that is likely the best mechanism for providing the
-needed functionality for %wpa_supplicant. Linux packet socket is an
+needed functionality for wpa_supplicant. Linux packet socket is an
 example of such a generic mechanism. If this is not available, a
 separate interface may need to be implemented to the network stack or
 driver. This is usually an intermediate or protocol driver that is
@@ -89,26 +89,27 @@
 a mechanism is not feasible, the interface can also be implemented
 directly in the device driver.
 
-The main %wpa_supplicant repository includes l2_packet implementations
-for Linux using packet sockets (l2_packet_linux.c), more portable
-version using libpcap/libdnet libraries (l2_packet_pcap.c; this
+The main wpa_supplicant repository includes l2_packet implementations
+for Linux using packet sockets (\ref l2_packet_linux.c), more portable
+version using libpcap/libdnet libraries (\ref l2_packet_pcap.c; this
 supports WinPcap, too), and FreeBSD specific version of libpcap
-interface (l2_packet_freebsd.c).
+interface (\ref l2_packet_freebsd.c).
 
 If the target operating system is supported by libpcap (receiving) and
-libdnet (sending), l2_packet_pcap.c can likely be used with minimal or
+libdnet (sending), \ref l2_packet_pcap.c can likely be used with minimal or
 no changes. If this is not a case or a proprietary interface for link
 layer is required, a new l2_packet module may need to be
-added. Alternatively, struct wpa_driver_ops::send_eapol() handler can
+added. Alternatively, for hostapd,
+struct \ref wpa_driver_ops::hapd_send_eapol() handler can
 be used to override the l2_packet library if the link layer access is
 integrated with the driver interface implementation.
 
 
 \section eloop_porting Event loop
 
-%wpa_supplicant uses a single process/thread model and an event loop
+wpa_supplicant uses a single process/thread model and an event loop
 to provide callbacks on events (registered timeout, received packet,
-signal). eloop.h defines the event loop interface. eloop.c is an
+signal). eloop.h defines the event loop interface. \ref eloop.c is an
 implementation of such an event loop using select() and sockets. This
 is suitable for most UNIX/POSIX systems. When porting to other
 operating systems, it may be necessary to replace that implementation
@@ -117,64 +118,64 @@
 
 \section ctrl_iface_porting Control interface
 
-%wpa_supplicant uses a \ref ctrl_iface_page "control interface"
+wpa_supplicant uses a \ref ctrl_iface_page "control interface"
 to allow external processed
 to get status information and to control the operations. Currently,
 this is implemented with socket based communication; both UNIX domain
 sockets and UDP sockets are supported. If the target OS does not
 support sockets, this interface will likely need to be modified to use
 another mechanism like message queues. The control interface is
-optional component, so it is also possible to run %wpa_supplicant
+optional component, so it is also possible to run wpa_supplicant
 without porting this part.
 
-The %wpa_supplicant side of the control interface is implemented in
-ctrl_iface.c. Matching client side is implemented as a control
-interface library in wpa_ctrl.c.
+The wpa_supplicant side of the control interface is implemented in
+\ref wpa_supplicant/ctrl_iface.c. Matching client side is implemented as a control
+interface library in \ref wpa_ctrl.c.
 
 
 \section entry_point Program entry point
 
-%wpa_supplicant defines a set of functions that can be used to
+wpa_supplicant defines a set of functions that can be used to
 initialize main supplicant processing. Each operating system has a
 mechanism for starting new processing or threads. This is usually a
 function with a specific set of arguments and calling convention. This
-function is responsible on initializing %wpa_supplicant.
+function is responsible on initializing wpa_supplicant.
 
-main.c includes an entry point for UNIX-like operating system, i.e.,
-main() function that uses command line arguments for setting
-parameters for %wpa_supplicant. When porting to other operating
-systems, similar OS-specific entry point implementation is needed. It
-can be implemented in a new file that is then linked with
-%wpa_supplicant instead of main.o. main.c is also a good example on
-how the initialization process should be done.
+\ref wpa_supplicant/main.c includes an entry point for UNIX-like
+operating system, i.e., main() function that uses command line arguments
+for setting parameters for wpa_supplicant. When porting to other
+operating systems, similar OS-specific entry point implementation is
+needed. It can be implemented in a new file that is then linked with
+wpa_supplicant instead of main.o. \ref wpa_supplicant/main.c is also a
+good example on how the initialization process should be done.
 
 The supplicant initialization functions are defined in
-wpa_supplicant_i.h. In most cases, the entry point function should
+\ref wpa_supplicant_i.h. In most cases, the entry point function should
 start by fetching configuration parameters. After this, a global
-%wpa_supplicant context is initialized with a call to
-wpa_supplicant_init(). After this, existing network interfaces can be
-added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then
+wpa_supplicant context is initialized with a call to
+\ref wpa_supplicant_init(). After this, existing network interfaces can be
+added with \ref wpa_supplicant_add_iface(). \ref wpa_supplicant_run() is then
 used to start the main event loop. Once this returns at program
-termination time, wpa_supplicant_deinit() is used to release global
+termination time, \ref wpa_supplicant_deinit() is used to release global
 context data.
 
-wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
+\ref wpa_supplicant_add_iface() and \ref wpa_supplicant_remove_iface() can be
 used dynamically to add and remove interfaces based on when
-%wpa_supplicant processing is needed for them. This can be done, e.g.,
+wpa_supplicant processing is needed for them. This can be done, e.g.,
 when hotplug network adapters are being inserted and ejected. It is
 also possible to do this when a network interface is being
-enabled/disabled if it is desirable that %wpa_supplicant processing
+enabled/disabled if it is desirable that wpa_supplicant processing
 for the interface is fully enabled/disabled at the same time.
 
 
 \section simple_build Simple build example
 
 One way to start a porting project is to begin with a very simple
-build of %wpa_supplicant with WPA-PSK support and once that is
+build of wpa_supplicant with WPA-PSK support and once that is
 building correctly, start adding features.
 
 Following command can be used to build very simple version of
-%wpa_supplicant:
+wpa_supplicant:
 
 \verbatim
 cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
@@ -192,7 +193,7 @@
 Once this version can be build successfully, the end result can be
 made functional by adding a proper program entry point (main*.c),
 driver interface (driver_*.c and matching CONFIG_DRIVER_* define for
-registration in drivers.c), configuration parser/writer (config_*.c),
+registration in \ref drivers.c), configuration parser/writer (config_*.c),
 and layer 2 packet access implementation (l2_packet_*.c). After these
 components have been added, the end result should be a working
 WPA/WPA2-PSK enabled supplicant.
diff --git a/doc/testing_tools.doxygen b/doc/testing_tools.doxygen
index 774bafb..d126524 100644
--- a/doc/testing_tools.doxygen
+++ b/doc/testing_tools.doxygen
@@ -6,7 +6,7 @@
 \ref unit_tests "Unit tests" |
 \ref wpa_trace "Tracing code" ]
 
-%wpa_supplicant source tree includes number of testing and development
+wpa_supplicant source tree includes number of testing and development
 tools that make it easier to test the programs without having to setup
 a full test setup with wireless cards. In addition, these tools can be
 used to implement automatic tests suites.
@@ -14,7 +14,7 @@
 \section eapol_test eapol_test - EAP peer and RADIUS client testing
 
 eapol_test is a program that links together the same EAP peer
-implementation that %wpa_supplicant is using and the RADIUS
+implementation that wpa_supplicant is using and the RADIUS
 authentication client code from hostapd. In addition, it has minimal
 glue code to combine these two components in similar ways to IEEE
 802.1X/EAPOL Authenticator state machines. In other words, it
@@ -34,7 +34,7 @@
 RADIUS authentication server.
 
 eapol_test uses the same build time configuration file, .config, as
-%wpa_supplicant. This file is used to select which EAP methods are
+wpa_supplicant. This file is used to select which EAP methods are
 included in eapol_test. This program is not built with the default
 Makefile target, so a separate make command needs to be used to
 compile the tool:
@@ -77,7 +77,7 @@
 configuration from test.conf against the RADIUS server running on the
 local host. A re-authentication is triggered to test fast
 re-authentication. The configuration file uses the same format for
-network blocks as %wpa_supplicant.
+network blocks as wpa_supplicant.
 
 
 \section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
@@ -85,8 +85,8 @@
 preauth_test is similar to eapol_test in the sense that in combines
 EAP peer implementation with something else, in this case, with WPA2
 pre-authentication. This tool can be used to test pre-authentication
-based on the code that %wpa_supplicant is using. As such, it tests
-both the %wpa_supplicant implementation and the functionality of an
+based on the code that wpa_supplicant is using. As such, it tests
+both the wpa_supplicant implementation and the functionality of an
 access point.
 
 preauth_test is built with:
@@ -112,7 +112,7 @@
 
 \section unit_tests Unit tests
 
-Number of the components (.c files) used in %wpa_supplicant define
+Number of the components (.c files) used in wpa_supplicant define
 their own unit tests for automated validation of the basic
 functionality. Most of the tests for cryptographic algorithms are
 using standard test vectors to validate functionality. These tests can
@@ -131,7 +131,7 @@
 
 \section wpa_trace Tracing code for developer debuggin
 
-%wpa_supplicant and hostapd can be built with tracing code that will
+wpa_supplicant and hostapd can be built with tracing code that will
 track and analyze memory allocations and other resource registrations
 and certain API uses. If incorrect use is detected, a backtrace of the
 call location (and/or allocation location) is shown. This can also be
diff --git a/eap_example/dh.conf b/eap_example/dh.conf
new file mode 100644
index 0000000..7bc8325
--- /dev/null
+++ b/eap_example/dh.conf
@@ -0,0 +1,5 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAP3V8IHq3H2DUlYywsvjYNuS17eCdt0mJo6/os6PHqdhgkMrPxF9u4Gr
+qKXq9e6GqmZYdjta30N3FkXaV924BJ0xOqb2TntiKg4u50/l6hSUneWt6UFBaizd
+XrqjNFIme/5RXMZ7RglXliBpCepAaFLMcKhOS4ulUyYYHSy+oqRjAgEC
+-----END DH PARAMETERS-----
diff --git a/eap_example/eap_example_server.c b/eap_example/eap_example_server.c
index 7097bca..a081b87 100644
--- a/eap_example/eap_example_server.c
+++ b/eap_example/eap_example_server.c
@@ -81,6 +81,7 @@
 	/* tparams.private_key = "server.key"; */
 	tparams.private_key = "server-key.pem";
 	/* tparams.private_key_passwd = "whatever"; */
+	tparams.dh_file = "dh.conf";
 
 	if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
 		printf("Failed to set TLS parameters\n");
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index d6d04c5..78a1506 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -134,6 +134,7 @@
 
 OBJS += src/common/ieee802_11_common.c
 OBJS += src/common/wpa_common.c
+OBJS += src/common/hw_features_common.c
 
 OBJS += src/eapol_auth/eapol_auth_sm.c
 
@@ -180,8 +181,6 @@
 OBJS += src/ap/ctrl_iface_ap.c
 endif
 
-OBJS += src/crypto/md5.c
-
 L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
 
 ifdef CONFIG_IAPP
@@ -214,6 +213,11 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
 ifdef CONFIG_IEEE80211W
 L_CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -554,33 +558,6 @@
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
 
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_schannel.c
-endif
-OBJS += src/crypto/crypto_cryptoapi.c
-OBJS_p += src/crypto/crypto_cryptoapi.c
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_nss.c
-LIBS += -lssl3
-endif
-OBJS += src/crypto/crypto_nss.c
-ifdef NEED_FIPS186_2_PRF
-OBJS += src/crypto/fips_prf_internal.c
-OBJS += src/crypto/sha1-internal.c
-endif
-LIBS += -lnss3
-LIBS_h += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
 CONFIG_CRYPTO=internal
@@ -687,7 +664,9 @@
 AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += src/crypto/aes-wrap.c
+endif
 ifdef NEED_AES_EAX
 AESOBJS += src/crypto/aes-eax.c
 NEED_AES_CTR=y
@@ -702,13 +681,17 @@
 AESOBJS += src/crypto/aes-omac1.c
 endif
 ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
 NEED_AES_DEC=y
 AESOBJS += src/crypto/aes-unwrap.c
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += src/crypto/aes-cbc.c
 endif
+endif
 ifdef NEED_AES_DEC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += src/crypto/aes-internal-dec.c
@@ -745,6 +728,10 @@
 OBJS += $(SHA1OBJS)
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/md5.c
+endif
+
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 OBJS += src/crypto/md5-internal.c
@@ -783,6 +770,9 @@
 OBJS += src/crypto/sha256-tlsprf.c
 endif
 endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+endif
 
 ifdef NEED_DH_GROUPS
 OBJS += src/crypto/dh_groups.c
@@ -807,8 +797,10 @@
 HOBJS += src/crypto/random.c
 HOBJS += src/utils/eloop.c
 HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
 HOBJS += src/crypto/md5.c
 endif
+endif
 
 ifdef CONFIG_RADIUS_SERVER
 L_CFLAGS += -DRADIUS_SERVER
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index f0e4604..e6f8c6a 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,49 @@
 ChangeLog for hostapd
 
+2015-03-15 - v2.4
+	* allow OpenSSL cipher configuration to be set for internal EAP server
+	  (openssl_ciphers parameter)
+	* fixed number of small issues based on hwsim test case failures and
+	  static analyzer reports
+	* fixed Accounting-Request to not include duplicated Acct-Session-Id
+	* add support for Acct-Multi-Session-Id in RADIUS Accounting messages
+	* add support for PMKSA caching with SAE
+	* add support for generating BSS Load element (bss_load_update_period)
+	* fixed channel switch from VHT to HT
+	* add INTERFACE-ENABLED and INTERFACE-DISABLED ctrl_iface events
+	* add support for learning STA IPv4/IPv6 addresses and configuring
+	  ProxyARP support
+	* dropped support for the madwifi driver interface
+	* add support for Suite B (128-bit and 192-bit level) key management and
+	  cipher suites
+	* fixed a regression with driver=wired
+	* extend EAPOL-Key msg 1/4 retry workaround for changing SNonce
+	* add BSS_TM_REQ ctrl_iface command to send BSS Transition Management
+	  Request frames and BSS-TM-RESP event to indicate response to such
+	  frame
+	* add support for EAP Re-Authentication Protocol (ERP)
+	* fixed AP IE in EAPOL-Key 3/4 when both WPA and FT was enabled
+	* fixed a regression in HT 20/40 coex Action frame parsing
+	* set stdout to be line-buffered
+	* add support for vendor specific VHT extension to enable 256 QAM rates
+	  (VHT-MCS 8 and 9) on 2.4 GHz band
+	* RADIUS DAS:
+	  - extend Disconnect-Request processing to allow matching of multiple
+	    sessions
+	  - support Acct-Multi-Session-Id as an identifier
+	  - allow PMKSA cache entry to be removed without association
+	* expire hostapd STA entry if kernel does not have a matching entry
+	* allow chanlist to be used to specify a subset of channels for ACS
+	* improve ACS behavior on 2.4 GHz band and allow channel bias to be
+	  configured with acs_chan_bias parameter
+	* do not reply to a Probe Request frame that includes DSS Parameter Set
+	  element in which the channel does not match the current operating
+	  channel
+	* add UPDATE_BEACON ctrl_iface command; this can be used to force Beacon
+	  frame contents to be updated and to start beaconing on an interface
+	  that used start_disabled=1
+	* fixed some RADIUS server failover cases
+
 2014-10-09 - v2.3
 	* fixed number of minor issues identified in static analyzer warnings
 	* fixed DFS and channel switch operation for multi-BSS cases
diff --git a/hostapd/Makefile b/hostapd/Makefile
index f10556b..b95cbcd 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,6 +6,7 @@
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+CFLAGS += $(EXTRA_CFLAGS)
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
@@ -115,6 +116,7 @@
 
 OBJS += ../src/common/ieee802_11_common.o
 OBJS += ../src/common/wpa_common.o
+OBJS += ../src/common/hw_features_common.o
 
 OBJS += ../src/eapol_auth/eapol_auth_sm.o
 
@@ -169,8 +171,6 @@
 OBJS += ../src/ap/ctrl_iface_ap.o
 endif
 
-OBJS += ../src/crypto/md5.o
-
 CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
 
 ifdef CONFIG_IAPP
@@ -203,6 +203,11 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
 ifdef CONFIG_IEEE80211W
 CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -222,6 +227,7 @@
 OBJS += ../src/common/sae.o
 NEED_ECC=y
 NEED_DH_GROUPS=y
+NEED_AP_MLME=y
 endif
 
 ifdef CONFIG_WNM
@@ -548,33 +554,6 @@
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
 
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_schannel.o
-endif
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.o
-endif
-LIBS += -lnss3
-LIBS_h += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
 CONFIG_CRYPTO=internal
@@ -681,7 +660,9 @@
 AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += ../src/crypto/aes-wrap.o
+endif
 ifdef NEED_AES_EAX
 AESOBJS += ../src/crypto/aes-eax.o
 NEED_AES_CTR=y
@@ -696,13 +677,17 @@
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
 NEED_AES_DEC=y
 AESOBJS += ../src/crypto/aes-unwrap.o
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
+endif
 ifdef NEED_AES_DEC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -738,6 +723,10 @@
 OBJS += $(SHA1OBJS)
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/md5.o
+endif
+
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 OBJS += ../src/crypto/md5-internal.o
@@ -779,6 +768,9 @@
 OBJS += ../src/crypto/sha256-kdf.o
 endif
 endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
+endif
 
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
@@ -803,8 +795,10 @@
 HOBJS += ../src/crypto/random.o
 HOBJS += ../src/utils/eloop.o
 HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
 HOBJS += ../src/crypto/md5.o
 endif
+endif
 
 ifdef CONFIG_RADIUS_SERVER
 CFLAGS += -DRADIUS_SERVER
@@ -969,7 +963,8 @@
 	$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
 	@$(E) "  LD " $@
 
-NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS)
+NOBJS += ../src/utils/common.o
 ifdef NEED_RC4
 ifdef CONFIG_INTERNAL_RC4
 NOBJS += ../src/crypto/rc4.o
diff --git a/hostapd/README b/hostapd/README
index ea016cc..366b199 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
 	  Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index a12f4a0..6846b99 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -216,15 +216,21 @@
 	FILE *f;
 	char buf[512], *pos, *start, *pos2;
 	int line = 0, ret = 0, num_methods;
-	struct hostapd_eap_user *user = NULL, *tail = NULL;
+	struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
 
 	if (!fname)
 		return 0;
 
 	if (os_strncmp(fname, "sqlite:", 7) == 0) {
+#ifdef CONFIG_SQLITE
 		os_free(conf->eap_user_sqlite);
 		conf->eap_user_sqlite = os_strdup(fname + 7);
 		return 0;
+#else /* CONFIG_SQLITE */
+		wpa_printf(MSG_ERROR,
+			   "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
+		return -1;
+#endif /* CONFIG_SQLITE */
 	}
 
 	f = fopen(fname, "r");
@@ -494,7 +500,7 @@
 
 	done:
 		if (tail == NULL) {
-			tail = conf->eap_user = user;
+			tail = new_user = user;
 		} else {
 			tail->next = user;
 			tail = user;
@@ -510,6 +516,18 @@
 
 	fclose(f);
 
+	if (ret == 0) {
+		user = conf->eap_user;
+		while (user) {
+			struct hostapd_eap_user *prev;
+
+			prev = user;
+			user = user->next;
+			hostapd_config_free_eap_user(prev);
+		}
+		conf->eap_user = new_user;
+	}
+
 	return ret;
 }
 #endif /* EAP_SERVER */
@@ -680,8 +698,14 @@
 		else if (os_strcmp(start, "FT-SAE") == 0)
 			val |= WPA_KEY_MGMT_FT_SAE;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_SUITEB
 		else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
 			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+		else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -757,6 +781,24 @@
 }
 
 
+static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
+{
+	char *pos;
+
+	/* for backwards compatibility, translate ' ' in conf str to ',' */
+	pos = val;
+	while (pos) {
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			*pos++ = ',';
+	}
+	if (freq_range_list_parse(&conf->acs_ch_list, val))
+		return -1;
+
+	return 0;
+}
+
+
 static int hostapd_parse_intlist(int **int_list, char *val)
 {
 	int *list;
@@ -1681,7 +1723,7 @@
 	char *str;
 
 	str = wpa_config_parse_string(pos, &slen);
-	if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+	if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
 		wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
 		os_free(str);
 		return -1;
@@ -1838,6 +1880,48 @@
 #endif /* CONFIG_WPS_NFC */
 
 
+#ifdef CONFIG_ACS
+static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
+					      char *pos)
+{
+	struct acs_bias *bias = NULL, *tmp;
+	unsigned int num = 0;
+	char *end;
+
+	while (*pos) {
+		tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
+		if (!tmp)
+			goto fail;
+		bias = tmp;
+
+		bias[num].channel = atoi(pos);
+		if (bias[num].channel <= 0)
+			goto fail;
+		pos = os_strchr(pos, ':');
+		if (!pos)
+			goto fail;
+		pos++;
+		bias[num].bias = strtod(pos, &end);
+		if (end == pos || bias[num].bias < 0.0)
+			goto fail;
+		pos = end;
+		if (*pos != ' ' && *pos != '\0')
+			goto fail;
+		num++;
+	}
+
+	os_free(conf->acs_chan_bias);
+	conf->acs_chan_bias = bias;
+	conf->num_acs_chan_bias = num;
+
+	return 0;
+fail:
+	os_free(bias);
+	return -1;
+}
+#endif /* CONFIG_ACS */
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
 			       struct hostapd_bss_config *bss,
 			       char *buf, char *pos, int line)
@@ -1886,7 +1970,7 @@
 			   line);
 	} else if (os_strcmp(buf, "ssid") == 0) {
 		bss->ssid.ssid_len = os_strlen(pos);
-		if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+		if (bss->ssid.ssid_len > SSID_MAX_LEN ||
 		    bss->ssid.ssid_len < 1) {
 			wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
 				   line, pos);
@@ -1897,7 +1981,7 @@
 	} 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) {
+		if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
 			wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
 				   line, pos);
 			os_free(str);
@@ -2129,6 +2213,14 @@
 		os_free(bss->nas_identifier);
 		bss->nas_identifier = os_strdup(pos);
 #ifndef CONFIG_NO_RADIUS
+	} else if (os_strcmp(buf, "radius_client_addr") == 0) {
+		if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid IP address '%s'",
+				   line, pos);
+			return 1;
+		}
+		bss->radius->force_client_addr = 1;
 	} else if (os_strcmp(buf, "auth_server_addr") == 0) {
 		if (hostapd_config_read_radius_addr(
 			    &bss->radius->auth_servers,
@@ -2140,6 +2232,15 @@
 			return 1;
 		}
 	} else if (bss->radius->auth_server &&
+		   os_strcmp(buf, "auth_server_addr_replace") == 0) {
+		if (hostapd_parse_ip_addr(pos,
+					  &bss->radius->auth_server->addr)) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid IP address '%s'",
+				   line, pos);
+			return 1;
+		}
+	} else if (bss->radius->auth_server &&
 		   os_strcmp(buf, "auth_server_port") == 0) {
 		bss->radius->auth_server->port = atoi(pos);
 	} else if (bss->radius->auth_server &&
@@ -2165,6 +2266,15 @@
 			return 1;
 		}
 	} else if (bss->radius->acct_server &&
+		   os_strcmp(buf, "acct_server_addr_replace") == 0) {
+		if (hostapd_parse_ip_addr(pos,
+					  &bss->radius->acct_server->addr)) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid IP address '%s'",
+				   line, pos);
+			return 1;
+		}
+	} else if (bss->radius->acct_server &&
 		   os_strcmp(buf, "acct_server_port") == 0) {
 		bss->radius->acct_server->port = atoi(pos);
 	} else if (bss->radius->acct_server &&
@@ -2265,12 +2375,11 @@
 		os_free(bss->ssid.wpa_passphrase);
 		bss->ssid.wpa_passphrase = os_strdup(pos);
 		if (bss->ssid.wpa_passphrase) {
-			os_free(bss->ssid.wpa_psk);
-			bss->ssid.wpa_psk = NULL;
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 			bss->ssid.wpa_passphrase_set = 1;
 		}
 	} else if (os_strcmp(buf, "wpa_psk") == 0) {
-		os_free(bss->ssid.wpa_psk);
+		hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
 		if (bss->ssid.wpa_psk == NULL)
 			return 1;
@@ -2278,8 +2387,7 @@
 		    pos[PMK_LEN * 2] != '\0') {
 			wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
 				   line, pos);
-			os_free(bss->ssid.wpa_psk);
-			bss->ssid.wpa_psk = NULL;
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 			return 1;
 		}
 		bss->ssid.wpa_psk->group = 1;
@@ -2458,12 +2566,15 @@
 				   line);
 			return 1;
 #else /* CONFIG_ACS */
+			conf->acs = 1;
 			conf->channel = 0;
 #endif /* CONFIG_ACS */
-		} else
+		} else {
 			conf->channel = atoi(pos);
+			conf->acs = conf->channel == 0;
+		}
 	} else if (os_strcmp(buf, "chanlist") == 0) {
-		if (hostapd_parse_intlist(&conf->chanlist, pos)) {
+		if (hostapd_parse_chanlist(conf, pos)) {
 			wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
 				   line);
 			return 1;
@@ -2490,6 +2601,12 @@
 			return 1;
 		}
 		conf->acs_num_scans = val;
+	} else if (os_strcmp(buf, "acs_chan_bias") == 0) {
+		if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
+				   line);
+			return -1;
+		}
 #endif /* CONFIG_ACS */
 	} else if (os_strcmp(buf, "dtim_period") == 0) {
 		bss->dtim_period = atoi(pos);
@@ -2690,6 +2807,8 @@
 		conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
 	} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
 		conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+	} else if (os_strcmp(buf, "vendor_vht") == 0) {
+		bss->vendor_vht = atoi(pos);
 #endif /* CONFIG_IEEE80211AC */
 	} else if (os_strcmp(buf, "max_listen_interval") == 0) {
 		bss->max_listen_interval = atoi(pos);
@@ -2718,7 +2837,7 @@
 		os_free(bss->wps_pin_requests);
 		bss->wps_pin_requests = os_strdup(pos);
 	} else if (os_strcmp(buf, "device_name") == 0) {
-		if (os_strlen(pos) > 32) {
+		if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
 			wpa_printf(MSG_ERROR, "Line %d: Too long "
 				   "device_name", line);
 			return 1;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 0e35aa6..86f1aa6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -23,6 +23,7 @@
 #include "utils/eloop.h"
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
+#include "crypto/tls.h"
 #include "drivers/driver.h"
 #include "radius/radius_client.h"
 #include "radius/radius_server.h"
@@ -39,6 +40,7 @@
 #include "ap/hs20.h"
 #include "ap/wnm_ap.h"
 #include "ap/wpa_auth.h"
+#include "ap/beacon.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "config_file.h"
@@ -1170,6 +1172,14 @@
 				return pos - buf;
 			pos += ret;
 		}
+		if (hapd->conf->wpa_key_mgmt &
+		    WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+			ret = os_snprintf(pos, end - pos,
+					  "WPA-EAP-SUITE-B-192 ");
+			if (os_snprintf_error(end - pos, ret))
+				return pos - buf;
+			pos += ret;
+		}
 
 		ret = os_snprintf(pos, end - pos, "\n");
 		if (os_snprintf_error(end - pos, ret))
@@ -1326,6 +1336,11 @@
 		if (os_snprintf_error(buflen, res))
 			return -1;
 		return res;
+	} else if (os_strcmp(cmd, "tls_library") == 0) {
+		res = tls_get_library_version(buf, buflen);
+		if (os_snprintf_error(buflen, res))
+			return -1;
+		return res;
 	}
 
 	return -1;
@@ -1692,6 +1707,45 @@
 	return res < 0 ? -1 : 0;
 }
 
+
+static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+	extern char wpa_trace_fail_func[256];
+	extern unsigned int wpa_trace_fail_after;
+	char *pos;
+
+	wpa_trace_fail_after = atoi(cmd);
+	pos = os_strchr(cmd, ':');
+	if (pos) {
+		pos++;
+		os_strlcpy(wpa_trace_fail_func, pos,
+			   sizeof(wpa_trace_fail_func));
+	} else {
+		wpa_trace_fail_after = 0;
+	}
+
+	return 0;
+#else /* WPA_TRACE_BFD */
+	return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
+				       char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+	extern char wpa_trace_fail_func[256];
+	extern unsigned int wpa_trace_fail_after;
+
+	return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
+			   wpa_trace_fail_func);
+#else /* WPA_TRACE_BFD */
+	return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -1902,6 +1956,9 @@
 	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
 		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
 			reply_len = -1;
+	} else if (os_strcmp(buf, "STOP_AP") == 0) {
+		if (hostapd_ctrl_iface_stop_ap(hapd))
+			reply_len = -1;
 #ifdef CONFIG_IEEE80211W
 #ifdef NEED_AP_MLME
 	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
@@ -1994,6 +2051,9 @@
 	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
 		if (hostapd_ctrl_iface_disable(hapd->iface))
 			reply_len = -1;
+	} else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
+		if (ieee802_11_set_beacon(hapd))
+			reply_len = -1;
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
 		if (hostapd_ctrl_iface_radar(hapd, buf + 6))
@@ -2013,6 +2073,12 @@
 	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
 		if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+		if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+		reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
+							reply_size);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
 		if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2206,8 +2272,11 @@
 	os_free(fname);
 
 	hapd->ctrl_sock = s;
-	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
-				 NULL);
+	if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+				     NULL) < 0) {
+		hostapd_ctrl_iface_deinit(hapd);
+		return -1;
+	}
 	hapd->msg_ctx = hapd;
 	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
 
@@ -2254,6 +2323,7 @@
 	}
 
 	dst = hapd->ctrl_dst;
+	hapd->ctrl_dst = NULL;
 	while (dst) {
 		prev = dst;
 		dst = dst->next;
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 42d59db..8afe457 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -87,6 +87,7 @@
 	u8 amf[2];
 	u8 sqn[6];
 	int set;
+	size_t res_len;
 };
 
 static struct milenage_parameters *milenage_db = NULL;
@@ -96,6 +97,7 @@
 #define EAP_AKA_RAND_LEN 16
 #define EAP_AKA_AUTN_LEN 16
 #define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MIN_LEN 4
 #define EAP_AKA_RES_MAX_LEN 16
 #define EAP_AKA_IK_LEN 16
 #define EAP_AKA_CK_LEN 16
@@ -124,7 +126,8 @@
 		"  ki CHAR(32) NOT NULL,"
 		"  opc CHAR(32) NOT NULL,"
 		"  amf CHAR(4) NOT NULL,"
-		"  sqn CHAR(12) NOT NULL"
+		"  sqn CHAR(12) NOT NULL,"
+		"  res_len INTEGER"
 		");";
 
 	printf("Adding database table for milenage information\n");
@@ -190,6 +193,10 @@
 			printf("Invalid sqn value in database\n");
 			return -1;
 		}
+
+		if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
+			m->res_len = atoi(argv[i]);
+		}
 	}
 
 	return 0;
@@ -206,8 +213,7 @@
 	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);
+		    "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
 	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
 			 NULL) != SQLITE_OK)
 		return NULL;
@@ -424,7 +430,7 @@
 	while (fgets(buf, sizeof(buf), f)) {
 		line++;
 
-		/* Parse IMSI Ki OPc AMF SQN */
+		/* Parse IMSI Ki OPc AMF SQN [RES_len] */
 		buf[sizeof(buf) - 1] = '\0';
 		if (buf[0] == '#')
 			continue;
@@ -515,7 +521,19 @@
 			ret = -1;
 			break;
 		}
-		pos = pos2 + 1;
+
+		if (pos2) {
+			pos = pos2 + 1;
+			m->res_len = atoi(pos);
+			if (m->res_len &&
+			    (m->res_len < EAP_AKA_RES_MIN_LEN ||
+			     m->res_len > EAP_AKA_RES_MAX_LEN)) {
+				printf("%s:%d - Invalid RES_len (%s)\n",
+				       fname, line, pos);
+				ret = -1;
+				break;
+			}
+		}
 
 		m->next = milenage_db;
 		milenage_db = m;
@@ -798,6 +816,10 @@
 		}
 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
 				  autn, ik, ck, res, &res_len);
+		if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
+		    m->res_len <= EAP_AKA_RES_MAX_LEN &&
+		    m->res_len < res_len)
+			res_len = m->res_len;
 	} else {
 		printf("Unknown IMSI: %s\n", imsi);
 #ifdef AKA_USE_FIXED_TEST_VALUES
diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db
index ecd06d7..c156a29 100644
--- a/hostapd/hlr_auc_gw.milenage_db
+++ b/hostapd/hlr_auc_gw.milenage_db
@@ -5,8 +5,10 @@
 # authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
 # dummy values will need to be included in this file.
 
-# IMSI Ki OPc AMF SQN
+# IMSI Ki OPc AMF SQN [RES_len]
 232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+# Example using truncated 32-bit RES instead of 64-bit default
+232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
 
 # These values are from Test Set 19 which has the AMF separation bit set to 1
 # and as such, is suitable for EAP-AKA' test.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2f6126c..90d1523 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -154,16 +154,27 @@
 # interference that may help choosing a better channel. This can also help fine
 # tune the ACS scan time in case a driver has different scan dwell times.
 #
+# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be
+# used to increase (or decrease) the likelihood of a specific channel to be
+# selected by the ACS algorithm. The total interference factor for each channel
+# gets multiplied by the specified bias value before finding the channel with
+# the lowest value. In other words, values between 0.0 and 1.0 can be used to
+# make a channel more likely to be picked while values larger than 1.0 make the
+# specified channel less likely to be picked. This can be used, e.g., to prefer
+# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
+# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).
+#
 # Defaults:
 #acs_num_scans=5
+#acs_chan_bias=1:0.8 6:0.8 11:0.8
 
 # Channel list restriction. This option allows hostapd to select one of the
-# provided channels when a channel should be automatically selected. This
-# is currently only used for DFS when the current channels becomes unavailable
-# due to radar interference, and is currently only useful when ieee80211h=1 is
-# set.
-# Default: not set (allow any enabled channel to be selected)
+# provided channels when a channel should be automatically selected.
+# Channel list can be provided as range using hyphen ('-') or individual
+# channels can be specified by space (' ') seperated values
+# Default: all channels allowed in selected hw_mode
 #chanlist=100 104 108 112 116
+#chanlist=1 6 11-13
 
 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
 beacon_int=100
@@ -497,9 +508,9 @@
 
 # If set non-zero, require stations to perform scans of overlapping
 # channels to test for stations which would be affected by 40 MHz traffic.
-# This parameter sets the interval in seconds between these scans. This
-# is useful only for testing that stations properly set the OBSS interval,
-# since the other parameters in the OBSS scan parameters IE are set to 0.
+# This parameter sets the interval in seconds between these scans. Setting this
+# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if
+# no co-existence issues with neighboring devices are found.
 #obss_interval=0
 
 ##### IEEE 802.11ac related configuration #####################################
@@ -877,6 +888,12 @@
 # 48 octets long.
 #nas_identifier=ap.example.com
 
+# RADIUS client forced local IP address for the access point
+# Normally the local IP address is determined automatically based on configured
+# IP addresses, but this field can be used to force a specific address to be
+# used, e.g., when the device has multiple IP addresses.
+#radius_client_addr=127.0.0.1
+
 # RADIUS authentication server
 #auth_server_addr=127.0.0.1
 #auth_server_port=1812
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 7009184..719d021 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #include <dirent.h>
 
 #include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/edit.h"
@@ -18,7 +19,7 @@
 
 static const char *hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *hostapd_cli_license =
@@ -541,7 +542,7 @@
 				      char *argv[])
 {
 	char buf[256];
-	char ssid_hex[2 * 32 + 1];
+	char ssid_hex[2 * SSID_MAX_LEN + 1];
 	char key_hex[2 * 64 + 1];
 	int i;
 
@@ -552,7 +553,7 @@
 	}
 
 	ssid_hex[0] = '\0';
-	for (i = 0; i < 32; i++) {
+	for (i = 0; i < SSID_MAX_LEN; i++) {
 		if (argv[0][i] == '\0')
 			break;
 		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
diff --git a/hostapd/main.c b/hostapd/main.c
index 0fe7ac8..0c8686a 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / main()
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -428,7 +428,7 @@
 		"hostapd v" VERSION_STR "\n"
 		"User space daemon for IEEE 802.11 AP management,\n"
 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-		"Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> "
+		"Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
 		"and contributors\n");
 }
 
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index 63cbc6f..b23ac17 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -8,23 +8,28 @@
 INCLUDES += external/libxml2/include
 INCLUDES += external/curl/include
 INCLUDES += external/webkit/Source/WebKit/gtk
-ifneq ($(wildcard external/icu),)
-INCLUDES += external/icu/icu4c/source/common
-else
+
+# We try to keep this compiling against older platform versions.
+# The new icu location (external/icu) exports its own headers, but
+# the older versions in external/icu4c don't, and we need to add those
+# headers to the include path by hand.
+ifeq ($(wildcard external/icu),)
 INCLUDES += external/icu4c/common
+else
+# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the
+# build (e.g., "mm -B" failed to build, but following that with "mm" allowed
+# the build to complete). For now, add the include directory manually here for
+# Android 5.0.
+ver = $(filter 5.0%,$(PLATFORM_VERSION))
+ifneq (,$(strip $(ver)))
+INCLUDES += external/icu/icu4c/source/common
+endif
 endif
 
 
-#GTKCFLAGS := $(shell pkg-config --cflags gtk+-2.0 webkit-1.0)
-#GTKLIBS := $(shell pkg-config --libs gtk+-2.0 webkit-1.0)
-#CFLAGS += $(GTKCFLAGS)
-#LIBS += $(GTKLIBS)
-
 L_CFLAGS += -DCONFIG_CTRL_IFACE
 L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
-L_CFLAGS += -DLIBXML_SCHEMAS_ENABLED
-L_CFLAGS += -DLIBXML_REGEXP_ENABLED
 
 OBJS = spp_client.c
 OBJS += oma_dm_client.c
@@ -53,8 +58,7 @@
 
 L_CFLAGS += -DEAP_TLS_OPENSSL
 
-#CFLAGS += $(shell xml2-config --cflags)
-#LIBS += $(shell xml2-config --libs)
+L_CFLAGS += -Wno-unused-parameter
 
 
 ########################
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index ca67b54..94cd5f1 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -67,7 +67,13 @@
 
 CFLAGS += $(shell xml2-config --cflags)
 LIBS += $(shell xml2-config --libs)
+
+# Allow static/custom linking of libcurl.
+ifdef CUST_CURL_LINKAGE
+LIBS += ${CUST_CURL_LINKAGE}
+else
 LIBS += -lcurl
+endif
 
 CFLAGS += -DEAP_TLS_OPENSSL
 LIBS += -lssl -lcrypto
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index 82e9106..5854b72 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -394,6 +394,10 @@
 	}
 
 	data = xml_node_get_text(ctx->xml, node);
+	if (data == NULL) {
+		wpa_printf(MSG_INFO, "Invalid data");
+		return DM_RESP_BAD_REQUEST;
+	}
 	wpa_printf(MSG_INFO, "Data: %s", data);
 	wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
 	write_summary(ctx, "Launch browser to URI '%s'", data);
@@ -428,6 +432,10 @@
 	}
 
 	data = xml_node_get_text(ctx->xml, node);
+	if (data == NULL) {
+		wpa_printf(MSG_INFO, "Invalid data");
+		return DM_RESP_BAD_REQUEST;
+	}
 	wpa_printf(MSG_INFO, "Data: %s", data);
 	getcert = xml_node_from_buf(ctx->xml, data);
 	xml_node_get_text_free(ctx->xml, data);
@@ -576,6 +584,11 @@
 	if (node) {
 		char *type;
 		type = xml_node_get_text(ctx->xml, node);
+		if (type == NULL) {
+			wpa_printf(MSG_ERROR, "Could not find type text");
+			os_free(uri);
+			return DM_RESP_BAD_REQUEST;
+		}
 		use_tnds = node &&
 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
 	}
@@ -648,6 +661,10 @@
 		return DM_RESP_BAD_REQUEST;
 	}
 	locuri = xml_node_get_text(ctx->xml, node);
+	if (locuri == NULL) {
+		wpa_printf(MSG_ERROR, "No LocURI node text found");
+		return DM_RESP_BAD_REQUEST;
+	}
 	wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
 		wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
@@ -755,6 +772,11 @@
 	if (node) {
 		char *type;
 		type = xml_node_get_text(ctx->xml, node);
+		if (type == NULL) {
+			wpa_printf(MSG_INFO, "Could not find type text");
+			os_free(locuri);
+			return DM_RESP_BAD_REQUEST;
+		}
 		use_tnds = node &&
 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
 	}
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a439bde..5cd823e 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -9,6 +9,9 @@
 #include "includes.h"
 #include <time.h>
 #include <sys/stat.h>
+#ifdef ANDROID
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
 
 #include "common.h"
 #include "utils/browser.h"
@@ -22,6 +25,8 @@
 #include "crypto/sha256.h"
 #include "osu_client.h"
 
+const char *spp_xsd_fname = "spp.xsd";
+
 
 void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
 {
@@ -397,9 +402,9 @@
 	}
 
 	node = get_child_node(ctx->xml, pps,
-			      "PolicyUpdate/TrustRoot");
+			      "Policy/PolicyUpdate/TrustRoot");
 	if (node == NULL) {
-		wpa_printf(MSG_INFO, "No PolicyUpdate/TrustRoot/CertURL found from PPS");
+		wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
 		xml_node_free(ctx->xml, pps);
 		return -1;
 	}
@@ -544,8 +549,9 @@
 	wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
 
 	if (!server_dnsname_suffix_match(ctx, fqdn)) {
-		wpa_printf(MSG_INFO, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
-			   fqdn);
+		wpa_printf(MSG_INFO,
+			   "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
+			   fqdn, (int) ctx->server_dnsname_count);
 		write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
 			     fqdn);
 		free(fqdn);
@@ -571,6 +577,21 @@
 		}
 	}
 
+#ifdef ANDROID
+	/* Allow processes running with Group ID as AID_WIFI,
+	 * to read files from SP/<fqdn> directory */
+	if (chown(fname, -1, AID_WIFI)) {
+		wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+	if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
+		wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+#endif /* ANDROID */
+
 	snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
 
 	if (os_file_exists(fname)) {
@@ -669,6 +690,10 @@
 	wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname);
 
 	str = xml_node_to_str(ctx->xml, pps);
+	if (str == NULL) {
+		wpa_printf(MSG_ERROR, "No node found");
+		return -1;
+	}
 	wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str);
 
 	snprintf(backup, sizeof(backup), "%s.bak", pps_fname);
@@ -2072,10 +2097,14 @@
 	}
 
 	ctx->no_reconnect = 1;
-	if (methods & 0x02)
+	if (methods & 0x02) {
+		wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
 		res = cmd_prov(ctx, url);
-	else if (methods & 0x01)
+	} else if (methods & 0x01) {
+		wpa_printf(MSG_DEBUG,
+			   "Calling cmd_oma_dm_prov from osu_connect");
 		res = cmd_oma_dm_prov(ctx, url);
+	}
 
 	wpa_printf(MSG_INFO, "Remove OSU network connection");
 	write_summary(ctx, "Remove OSU network connection");
@@ -2117,7 +2146,7 @@
 	snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
 	osu = parse_osu_providers(fname, &osu_count);
 	if (osu == NULL) {
-		wpa_printf(MSG_INFO, "Could not any OSU providers from %s",
+		wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
 			   fname);
 		write_result(ctx, "No OSU providers available");
 		return -1;
@@ -2268,12 +2297,19 @@
 		}
 
 		if (connect == 2) {
-			if (last->methods & 0x02)
+			if (last->methods & 0x02) {
+				wpa_printf(MSG_DEBUG,
+					   "Calling cmd_prov from cmd_osu_select");
 				ret = cmd_prov(ctx, last->url);
-			else if (last->methods & 0x01)
+			} else if (last->methods & 0x01) {
+				wpa_printf(MSG_DEBUG,
+					   "Calling cmd_oma_dm_prov from cmd_osu_select");
 				ret = cmd_oma_dm_prov(ctx, last->url);
-			else
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "No supported OSU provisioning method");
 				ret = -1;
+			}
 		} else if (connect)
 			ret = osu_connect(ctx, last->bssid, last->osu_ssid,
 					  last->url, last->methods,
@@ -2343,8 +2379,8 @@
 }
 
 
-static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
-			const char *pps_fname, const char *ca_fname)
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+		       const char *pps_fname, const char *ca_fname)
 {
 	xml_node_t *pps, *node;
 	char pps_fname_buf[300];
@@ -2371,12 +2407,12 @@
 		} else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
 					  sizeof(buf)) < 0) {
 			wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
-			return;
+			return -1;
 		}
 		os_free(ctx->fqdn);
 		ctx->fqdn = os_strdup(buf);
 		if (ctx->fqdn == NULL)
-			return;
+			return -1;
 		wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
 			   buf);
 		os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
@@ -2391,14 +2427,14 @@
 	if (!os_file_exists(pps_fname)) {
 		wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
 			   pps_fname);
-		return;
+		return -1;
 	}
 	wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
 
 	if (ca_fname && !os_file_exists(ca_fname)) {
 		wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
 			   ca_fname);
-		return;
+		return -1;
 	}
 	wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
 	ctx->ca_fname = ca_fname;
@@ -2406,7 +2442,7 @@
 	pps = node_from_file(ctx->xml, pps_fname);
 	if (pps == NULL) {
 		wpa_printf(MSG_INFO, "Could not read PPS MO");
-		return;
+		return -1;
 	}
 
 	if (!ctx->fqdn) {
@@ -2414,18 +2450,18 @@
 		node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
 		if (node == NULL) {
 			wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
-			return;
+			return -1;
 		}
 		tmp = xml_node_get_text(ctx->xml, node);
 		if (tmp == NULL) {
 			wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
-			return;
+			return -1;
 		}
 		ctx->fqdn = os_strdup(tmp);
 		xml_node_get_text_free(ctx->xml, tmp);
 		if (!ctx->fqdn) {
 			wpa_printf(MSG_INFO, "No FQDN known");
-			return;
+			return -1;
 		}
 	}
 
@@ -2474,7 +2510,7 @@
 	}
 	if (!address) {
 		wpa_printf(MSG_INFO, "Server URL not known");
-		return;
+		return -1;
 	}
 
 	write_summary(ctx, "Wait for IP address for subscriptiom remediation");
@@ -2497,6 +2533,7 @@
 	xml_node_get_text_free(ctx->xml, cred_username);
 	str_clear_free(cred_password);
 	xml_node_free(ctx->xml, pps);
+	return 0;
 }
 
 
@@ -2787,17 +2824,21 @@
 		char *name = ctx->icon_filename[j];
 		size_t name_len = os_strlen(name);
 
-		wpa_printf(MSG_INFO, "Looking for icon file name '%s' match",
-			   name);
+		wpa_printf(MSG_INFO,
+			   "[%i] Looking for icon file name '%s' match",
+			   j, name);
 		for (i = 0; i < cert->num_logo; i++) {
 			struct http_logo *logo = &cert->logo[i];
 			size_t uri_len = os_strlen(logo->uri);
 			char *pos;
 
-			wpa_printf(MSG_INFO, "Comparing to '%s' uri_len=%d name_len=%d",
-				   logo->uri, (int) uri_len, (int) name_len);
-			if (uri_len < 1 + name_len)
+			wpa_printf(MSG_INFO,
+				   "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+				   i, logo->uri, (int) uri_len, (int) name_len);
+			if (uri_len < 1 + name_len) {
+				wpa_printf(MSG_INFO, "URI Length is too short");
 				continue;
+			}
 			pos = &logo->uri[uri_len - name_len - 1];
 			if (*pos != '/')
 				continue;
@@ -2824,17 +2865,30 @@
 		for (i = 0; i < cert->num_logo; i++) {
 			struct http_logo *logo = &cert->logo[i];
 
-			if (logo->hash_len != 32)
+			if (logo->hash_len != 32) {
+				wpa_printf(MSG_INFO,
+					   "[%i][%i] Icon hash length invalid (should be 32): %d",
+					   j, i, (int) logo->hash_len);
 				continue;
+			}
 			if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
 				found = 1;
 				break;
 			}
+
+			wpa_printf(MSG_DEBUG,
+				   "[%u][%u] Icon hash did not match", j, i);
+			wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
+					  logo->hash, 32);
+			wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
+					  ctx->icon_hash[j], 32);
 		}
 
 		if (!found) {
-			wpa_printf(MSG_INFO, "No icon hash match found");
-			write_result(ctx, "No icon hash match found");
+			wpa_printf(MSG_INFO,
+				   "No icon hash match (by hash) found");
+			write_result(ctx,
+				     "No icon hash match (by hash) found");
 			return -1;
 		}
 	}
@@ -2932,6 +2986,7 @@
 	       "    [-w<wpa_supplicant ctrl_iface dir>] "
 	       "[-r<result file>] [-f<debug file>] \\\n"
 	       "    [-s<summary file>] \\\n"
+	       "    [-x<spp.xsd file name>] \\\n"
 	       "    <command> [arguments..]\n"
 	       "commands:\n"
 	       "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
@@ -2973,7 +3028,7 @@
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
+		c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -3011,6 +3066,9 @@
 		case 'w':
 			wpas_ctrl_path = optarg;
 			break;
+		case 'x':
+			spp_xsd_fname = optarg;
+			break;
 		case 'h':
 		default:
 			usage();
@@ -3066,10 +3124,11 @@
 		if (argc - optind < 2)
 			wpa_printf(MSG_ERROR, "Server URL missing from command line");
 		else
-			cmd_sub_rem(&ctx, argv[optind + 1],
-				    argc > optind + 2 ? argv[optind + 2] : NULL,
-				    argc > optind + 3 ? argv[optind + 3] :
-				    NULL);
+			ret = cmd_sub_rem(&ctx, argv[optind + 1],
+					  argc > optind + 2 ?
+					  argv[optind + 2] : NULL,
+					  argc > optind + 3 ?
+					  argv[optind + 3] : NULL);
 	} else if (strcmp(argv[optind], "pol_upd") == 0) {
 		if (argc - optind < 2) {
 			usage();
@@ -3084,6 +3143,7 @@
 			exit(0);
 		}
 		ctx.ca_fname = argv[optind + 2];
+		wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
 		cmd_prov(&ctx, argv[optind + 1]);
 	} else if (strcmp(argv[optind], "sim_prov") == 0) {
 		if (argc - optind < 2) {
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index 302a050..cc1a0bf 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -21,6 +21,8 @@
 #include "osu_client.h"
 
 
+extern const char *spp_xsd_fname;
+
 static int hs20_spp_update_response(struct hs20_osu_client *ctx,
 				    const char *session_id,
 				    const char *spp_status,
@@ -59,7 +61,7 @@
 		return -1;
 	}
 
-	ret = xml_validate(xctx, node, "spp.xsd", &err);
+	ret = xml_validate(xctx, node, spp_xsd_fname, &err);
 	if (ret < 0) {
 		wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
 		write_summary(ctx, "SPP XML schema validation failed");
@@ -952,7 +954,9 @@
 		return -1;
 	}
 
-	wpa_printf(MSG_INFO, "Credential provisioning requested");
+	wpa_printf(MSG_INFO,
+		   "Credential provisioning requested - URL: %s ca_fname: %s",
+		   url, ctx->ca_fname ? ctx->ca_fname : "N/A");
 
 	os_free(ctx->server_url);
 	ctx->server_url = os_strdup(url);
diff --git a/hs20/server/ca/clean.sh b/hs20/server/ca/clean.sh
index c69a1f5..c72dcbd 100755
--- a/hs20/server/ca/clean.sh
+++ b/hs20/server/ca/clean.sh
@@ -5,6 +5,9 @@
 done
 
 rm -f openssl.cnf.tmp
-rm -r demoCA
+if [ -d demoCA ]; then
+    rm -r demoCA
+fi
 rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
+rm -f my-openssl.cnf my-openssl-root.cnf
 #rm -r rootCA
diff --git a/hs20/server/ca/openssl-root.cnf b/hs20/server/ca/openssl-root.cnf
index 5b220fe..5bc50be 100644
--- a/hs20/server/ca/openssl-root.cnf
+++ b/hs20/server/ca/openssl-root.cnf
@@ -69,8 +69,8 @@
 attributes		= req_attributes
 x509_extensions	= v3_ca	# The extentions to add to the self signed cert
 
-input_password = whatever
-output_password = whatever
+input_password = @PASSWORD@
+output_password = @PASSWORD@
 
 string_mask = utf8only
 
diff --git a/hs20/server/ca/openssl.cnf b/hs20/server/ca/openssl.cnf
index a939f08..6141013 100644
--- a/hs20/server/ca/openssl.cnf
+++ b/hs20/server/ca/openssl.cnf
@@ -80,8 +80,8 @@
 attributes		= req_attributes
 x509_extensions	= v3_ca	# The extentions to add to the self signed cert
 
-input_password = whatever
-output_password = whatever
+input_password = @PASSWORD@
+output_password = @PASSWORD@
 
 string_mask = utf8only
 
@@ -95,7 +95,7 @@
 localityName_default		= Tuusula
 
 0.organizationName		= Organization Name (eg, company)
-0.organizationName_default	= w1.fi
+0.organizationName_default	= @DOMAIN@
 
 ##organizationalUnitName		= Organizational Unit Name (eg, section)
 #organizationalUnitName_default	=
@@ -117,10 +117,10 @@
 authorityKeyIdentifier=keyid:always,issuer
 basicConstraints = critical, CA:true, pathlen:0
 keyUsage = critical, cRLSign, keyCertSign
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
 # For SP intermediate CA
 #subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
-#nameConstraints=permitted;DNS:.w1.fi
+#nameConstraints=permitted;DNS:.@DOMAIN@
 #1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
 
 [ v3_osu_server ]
@@ -150,16 +150,16 @@
 #value2=SEQUENCE:HashAlgAndValueSHA1
 [HashAlgAndValueSHA256]
 hashAlg=SEQUENCE:sha256_alg
-hashValue=FORMAT:HEX,OCTETSTRING:4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
 [HashAlgAndValueSHA1]
 hashAlg=SEQUENCE:sha1_alg
-hashValue=FORMAT:HEX,OCTETSTRING:5e1d5085676eede6b02da14d31c523ec20ffba0b
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
 [sha256_alg]
 algorithm=OID:sha256
 [sha1_alg]
 algorithm=OID:sha1
 [URI]
-uri=IA5STRING:http://osu.w1.fi/w1fi_logo.png
+uri=IA5STRING:@LOGO_URI@
 [LogotypeImageInfo]
 # default value color(1), component optional
 #type=IMP:0,INTEGER:1
@@ -184,7 +184,7 @@
 basicConstraints=CA:FALSE
 subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
 #@ALTNAME@
 extendedKeyUsage = clientAuth
 
@@ -194,7 +194,7 @@
 basicConstraints=critical, CA:FALSE
 subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
 #@ALTNAME@
 extendedKeyUsage = critical, serverAuth
 keyUsage = critical, keyEncipherment
diff --git a/hs20/server/ca/setup.sh b/hs20/server/ca/setup.sh
index f61bf73..78abccc 100755
--- a/hs20/server/ca/setup.sh
+++ b/hs20/server/ca/setup.sh
@@ -5,6 +5,67 @@
 fi
 export OPENSSL_CONF=$PWD/openssl.cnf
 PASS=whatever
+if [ -z "$DOMAIN" ]; then
+    DOMAIN=w1.fi
+fi
+COMPANY=w1.fi
+OPER_ENG="engw1.fi TESTING USE"
+OPER_FI="finw1.fi TESTIKÄYTTÖ"
+CNR="Hotspot 2.0 Trust Root CA - 99"
+CNO="ocsp.$DOMAIN"
+CNV="osu-revoked.$DOMAIN"
+CNOC="osu-client.$DOMAIN"
+OSU_SERVER_HOSTNAME="osu.$DOMAIN"
+DEBUG=0
+OCSP_URI="http://$CNO:8888/"
+LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
+LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
+LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
+
+# Command line overrides
+USAGE=$( cat <<EOF
+Usage:\n
+# -c:  Company name, used to generate Subject name CN for Intermediate CA\n
+# -C:  Subject name CN of the Root CA ($CNR)\n
+# -D:  Enable debugging (set -x, etc)\n
+# -g:  Logo sha1 hash ($LOGO_HASH1)\n
+# -G:  Logo sha256 hash ($LOGO_HASH256)\n
+# -h:  Show this help message\n
+# -l:  Logo URI ($LOGO_URI)\n
+# -m:  Domain ($DOMAIN)\n
+# -o:  Subject name CN for OSU-Client Server ($CNOC)\n
+# -O:  Subject name CN for OCSP Server ($CNO)\n
+# -p:  passphrase for private keys ($PASS)\n
+# -r:  Operator-english ($OPER_ENG)\n
+# -R:  Operator-finish ($OPER_FI)\n
+# -S:  OSU Server name ($OSU_SERVER_HOSTNAME)\n
+# -u:  OCSP-URI ($OCSP_URI)\n
+# -V:  Subject name CN for OSU-Revoked Server ($CNV)\n
+EOF
+)
+
+while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
+  do
+  case $flag in
+      c) COMPANY=$OPTARG;;
+      C) CNR=$OPTARG;;
+      D) DEBUG=1;;
+      g) LOGO_HASH1=$OPTARG;;
+      G) LOGO_HASH256=$OPTARG;;
+      h) echo -e $USAGE; exit 0;;
+      l) LOGO_URI=$OPTARG;;
+      m) DOMAIN=$OPTARG;;
+      o) CNOC=$OPTARG;;
+      O) CNO=$OPTARG;;
+      p) PASS=$OPTARG;;
+      r) OPER_ENG=$OPTARG;;
+      R) OPER_FI=$OPTARG;;
+      S) OSU_SERVER_HOSTNAME=$OPTARG;;
+      u) OCSP_URI=$OPTARG;;
+      V) CNV=$OPTARG;;
+      *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
+  esac
+done
 
 fail()
 {
@@ -16,7 +77,25 @@
 echo "---[ Root CA ]----------------------------------------------------------"
 echo
 
-cat openssl-root.cnf | sed "s/#@CN@/commonName_default = Hotspot 2.0 Trust Root CA - 99/" > openssl.cnf.tmp
+if [ $DEBUG = 1 ]
+then
+    set -x
+fi
+
+# Set the passphrase and some other common config accordingly.
+cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
+ > my-openssl-root.cnf
+
+cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
+sed "s,@OCSP_URI@,$OCSP_URI," |
+sed "s,@LOGO_URI@,$LOGO_URI," |
+sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
+sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
+sed "s/@DOMAIN@/$DOMAIN/" \
+ > my-openssl.cnf
+
+
+cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
 mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
 touch rootCA/index.txt
 if [ -e rootCA/private/cakey.pem ]; then
@@ -26,6 +105,8 @@
     $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
     echo " * Sign Root CA certificate"
     $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
+    $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
+    sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
 fi
 if [ ! -e rootCA/crlnumber ]; then
     echo 00 > rootCA/crlnumber
@@ -35,7 +116,7 @@
 echo "---[ Intermediate CA ]--------------------------------------------------"
 echo
 
-cat openssl.cnf | sed "s/#@CN@/commonName_default = w1.fi Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
 mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
 touch demoCA/index.txt
 if [ -e demoCA/private/cakey.pem ]; then
@@ -47,6 +128,8 @@
     $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
     # horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
     openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
+    $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
+    sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
 fi
 if [ ! -e demoCA/crlnumber ]; then
     echo 00 > demoCA/crlnumber
@@ -56,45 +139,46 @@
 echo "OCSP responder"
 echo
 
-cat openssl.cnf | sed "s/#@CN@/commonName_default = ocsp.w1.fi/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
 $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
 
 echo
 echo "---[ Server - to be revoked ] ------------------------------------------"
 echo
 
-cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-revoked.w1.fi/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
 $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
 $OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
 $OPENSSL ca -revoke server-revoked.pem -key $PASS
 
 echo
 echo "---[ Server - with client ext key use ] ---------------------------------"
+echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
 echo
 
-cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-client.w1.fi/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
 
 echo
 echo "---[ User ]-------------------------------------------------------------"
 echo
 
-cat openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
 
 echo
 echo "---[ Server ]-----------------------------------------------------------"
 echo
 
-ALT="DNS:osu.w1.fi"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engw1.fi TESTING USE"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:finw1.fi TESTIKÄYTTÖ"
+ALT="DNS:$OSU_SERVER_HOSTNAME"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
 
-cat openssl.cnf |
-	sed "s/#@CN@/commonName_default = osu.w1.fi/" |
+cat my-openssl.cnf |
+	sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
 	sed "s/^##organizationalUnitName/organizationalUnitName/" |
 	sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
 	sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
@@ -113,7 +197,7 @@
 echo "---[ CRL ]---------------------------------------------------------------"
 echo
 
-$OPENSSL ca -config $PWD/openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
+$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
 
 echo
 echo "---[ Verify ]------------------------------------------------------------"
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 80985f7..001d6f2 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -100,6 +100,21 @@
 # the examples as-is for initial testing).
 cp -r www /home/user/hs20-server
 
+# Build local keys and certs
+cd ca
+# Display help options.
+./setup.sh -h
+
+# Remove old keys, fill in appropriate values, and generate your keys.
+# For instance:
+./clean.sh
+rm -fr rootCA"
+old_hostname=myserver.local
+./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" -d $old_hostname \
+   -I "Hotspot 2.0 Intermediate CA - CT" -o $old_hostname-osu-client \
+   -O $old_hostname-oscp -p lanforge -S $old_hostname \
+   -V $old_hostname-osu-revoked \
+   -m local -u http://$old_hostname:8888/
 
 # Configure subscription policies
 mkdir -p /home/user/hs20-server/spp/policy
@@ -156,6 +171,50 @@
 ./hostapd -B as-sql.conf
 
 
+OSEN RADIUS server configuration notes
+
+The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
+configuration in it. For example:
+
+# hostapd-radius config for the radius used by the OSEN AP
+interface=eth0#0
+driver=none
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+ctrl_interface=/var/run/hostapd
+ctrl_interface_group=0
+eap_server=1
+eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
+server_id=ben-ota-2-osen
+radius_server_auth_port=1811
+radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
+
+ca_cert=/home/user/hs20-server/ca/ca.pem
+server_cert=/home/user/hs20-server/ca/server.pem
+private_key=/home/user/hs20-server/ca/server.key
+private_key_passwd=whatever
+
+ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
+
+The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
+similar to this, and should coorelate with the osu_nai entry in
+the non-OSEN VAP config file.  For instance:
+
+# cat hostapd-osen.eap_user
+# For OSEN authentication (Hotspot 2.0 Release 2)
+"osen@w1.fi"      WFA-UNAUTH-TLS
+
+
+# Run OCSP server:
+cd /home/user/hs20-server/ca
+./ocsp-responder.sh&
+
+# Update cache (This should be run periodically)
+./ocsp-update-cache.sh
+
+
 Configure web server
 --------------------
 
@@ -172,6 +231,8 @@
         </Directory>
 
 Update SSL configuration to use the OSU server certificate/key.
+They keys and certs are called 'server.key' and 'server.pem' from
+ca/setup.sh.
 
 Enable default-ssl site and restart Apache2:
   sudo a2ensite default-ssl
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 4d77d0e..33e3fa1 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -103,6 +103,28 @@
 }
 
 
+static void db_update_session_machine_managed(struct hs20_svc *ctx,
+					      const char *user,
+					      const char *realm,
+					      const char *sessionid,
+					      const int pw_mm)
+{
+	char *sql;
+
+	sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
+			      pw_mm ? "1" : "0", sessionid, user, realm);
+	if (sql == NULL)
+		return;
+	debug_print(ctx, 1, "DB: %s", sql);
+	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+		debug_print(ctx, 1,
+			    "Failed to update session machine_managed: %s",
+			    sqlite3_errmsg(ctx->db));
+	}
+	sqlite3_free(sql);
+}
+
+
 static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
 			       const char *realm, const char *sessionid,
 			       xml_node_t *node)
@@ -1378,6 +1400,11 @@
 
 	debug_print(ctx, 1, "Request DB subscription registration on success "
 		    "notification");
+	if (machine_managed) {
+		db_update_session_password(ctx, user, realm, session_id, pw);
+		db_update_session_machine_managed(ctx, user, realm, session_id,
+						  machine_managed);
+	}
 	db_add_session_pps(ctx, user, realm, session_id, pps);
 
 	hs20_eventlog_node(ctx, user, realm, session_id,
@@ -2169,7 +2196,9 @@
 		session_id = xml_node_get_attr_value_ns(ctx->xml, node,
 							SPP_NS_URI,
 							"sessionID");
-		debug_print(ctx, 1, "SPP message failed validation");
+		debug_print(ctx, 1,
+			    "SPP message failed validation, xsd file: %s  xml-error: %s",
+			    fname, xml_err);
 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
 				   "SPP message failed validation", node);
 		hs20_eventlog(ctx, auth_user, auth_realm, session_id,
diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php
index a626704..aeb2f68 100644
--- a/hs20/server/www/signup.php
+++ b/hs20/server/www/signup.php
@@ -17,7 +17,7 @@
 
 $row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch();
 if ($row == false) {
-   die("Session not found");
+   die("Session not found for id: $id");
 }
 $realm = $row['realm'];
 
diff --git a/patches/openssl-0.9.8zf-tls-extensions.patch b/patches/openssl-0.9.8zf-tls-extensions.patch
new file mode 100644
index 0000000..3a8f90e
--- /dev/null
+++ b/patches/openssl-0.9.8zf-tls-extensions.patch
@@ -0,0 +1,398 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
+--- openssl-0.9.8zf.orig/ssl/s3_clnt.c	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_clnt.c	2015-03-24 16:19:14.043911769 +0200
+@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
+         goto f_err;
+     }
+ 
++#ifndef OPENSSL_NO_TLSEXT
++    /* check if we want to resume the session based on external pre-shared secret */
++    if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
++        SSL_CIPHER *pref_cipher = NULL;
++
++        s->session->master_key_length = sizeof(s->session->master_key);
++        if (s->tls_session_secret_cb(s, s->session->master_key,
++				     &s->session->master_key_length,
++				     NULL, &pref_cipher,
++				     s->tls_session_secret_cb_arg)) {
++            s->session->cipher = pref_cipher ?
++		    pref_cipher : ssl_get_cipher_by_char(s, p + j);
++	    s->s3->flags |= SSL3_FLAGS_CCS_OK;
++	}
++    }
++#endif /* OPENSSL_NO_TLSEXT */
++
+     if (j != 0 && j == s->session->session_id_length
+         && memcmp(p, s->session->session_id, j) == 0) {
+         if (s->sid_ctx_length != s->session->sid_ctx_length
+@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
+ {
+     int ok;
+     long n;
+-    /*
+-     * If we have no ticket or session ID is non-zero length (a match of a
+-     * non-zero session length would never reach here) it cannot be a resumed
+-     * session.
+-     */
+-    if (!s->session->tlsext_tick || s->session->session_id_length)
++    /* If we have no ticket it cannot be a resumed session. */
++    if (!s->session->tlsext_tick)
+         return 1;
+     /*
+      * this function is called when we really expect a Certificate message,
+diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
+--- openssl-0.9.8zf.orig/ssl/s3_srvr.c	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_srvr.c	2015-03-24 16:23:34.567909681 +0200
+@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
+         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+         goto err;
+     }
++
++    /* Check if we want to use external pre-shared secret for this
++     * handshake for not reused session only. We need to generate
++     * server_random before calling tls_session_secret_cb in order to allow
++     * SessionTicket processing to use it in key derivation. */
++    {
++        unsigned long Time;
++	unsigned char *pos;
++	Time = (unsigned long)time(NULL);			/* Time */
++	pos = s->s3->server_random;
++	l2n(Time, pos);
++	if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
++		al = SSL_AD_INTERNAL_ERROR;
++		goto f_err;
++	}
++    }
++
++    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
++	SSL_CIPHER *pref_cipher = NULL;
++
++	s->session->master_key_length = sizeof(s->session->master_key);
++	if (s->tls_session_secret_cb(s, s->session->master_key,
++				     &s->session->master_key_length, 
++				     ciphers, &pref_cipher,
++				     s->tls_session_secret_cb_arg)) {
++	    s->hit = 1;
++	    s->session->ciphers = ciphers;
++	    s->session->verify_result = X509_V_OK;
++
++	    ciphers = NULL;
++
++	    /* check if some cipher was preferred by call back */
++	    pref_cipher = pref_cipher ? pref_cipher :
++		    ssl3_choose_cipher(s, s->session->ciphers,
++				       SSL_get_ciphers(s));
++	    if (pref_cipher == NULL) {
++		al = SSL_AD_HANDSHAKE_FAILURE;
++		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
++		goto f_err;
++	    }
++
++	    s->session->cipher = pref_cipher;
++
++	    if (s->cipher_list)
++		sk_SSL_CIPHER_free(s->cipher_list);
++
++	    if (s->cipher_list_by_id)
++		sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++	    s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++	    s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++	}
++    }
+ #endif
+     /*
+      * Worst case, we will use the NULL compression, but if we have other
+@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
+     unsigned char *buf;
+     unsigned char *p, *d;
+     int i, sl;
+-    unsigned long l, Time;
++    unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++    unsigned long Time;
++#endif
+ 
+     if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
+         buf = (unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+         p = s->s3->server_random;
++        /* Generate server_random if it was not needed previously */
+         Time = (unsigned long)time(NULL); /* Time */
+         l2n(Time, p);
+         if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
+             return -1;
++#endif
+         /* Do the message type and length last */
+         d = p = &(buf[4]);
+ 
+diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
+--- openssl-0.9.8zf.orig/ssl/ssl_err.c	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_err.c	2015-03-24 16:35:58.627903717 +0200
+@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
+     {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+     {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+     {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++    {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+     {0, NULL}
+ };
+ 
+diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
+--- openssl-0.9.8zf.orig/ssl/ssl.h	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl.h	2015-03-24 16:25:44.339908641 +0200
+@@ -349,6 +349,7 @@ extern "C" {
+  * function parameters used to prototype callbacks in SSL_CTX.
+  */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st {
+@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
+ 
+ DECLARE_STACK_OF(SSL_CIPHER)
+ 
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
++					    int len, void *arg);
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
++					STACK_OF(SSL_CIPHER) *peer_ciphers,
++					SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st {
+     int version;
+@@ -1116,6 +1123,18 @@ struct ssl_st {
+     int tlsext_ocsp_resplen;
+     /* RFC4507 session ticket expected to be received or sent */
+     int tlsext_ticket_expected;
++
++    /* TLS Session Ticket extension override */
++    TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++    /* TLS Session Ticket extension callback */
++    tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++    void *tls_session_ticket_ext_cb_arg;
++
++    /* TLS pre-shared secret session resumption */
++    tls_session_secret_cb_fn tls_session_secret_cb;
++    void *tls_session_secret_cb_arg;
++
+     SSL_CTX *initial_ctx;       /* initial ctx, used to store sessions */
+ #  define session_ctx initial_ctx
+ # else
+@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id, void *cm);
+ # endif
+ 
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s,
++			      tls_session_secret_cb_fn tls_session_secret_cb,
++			      void *arg);
++
+ /* BEGIN ERROR CODES */
+ /*
+  * The following lines are auto generated by the script mkerr.pl. Any changes
+@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
+ # define SSL_F_TLS1_ENC                                   210
+ # define SSL_F_TLS1_SETUP_KEY_BLOCK                       211
+ # define SSL_F_WRITE_PENDING                              212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT                  213
+ 
+ /* Reason codes. */
+ # define SSL_R_APP_DATA_IN_HANDSHAKE                      100
+diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
+--- openssl-0.9.8zf.orig/ssl/ssl_sess.c	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_sess.c	2015-03-24 16:28:04.819907515 +0200
+@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+     return (s->session_timeout);
+ }
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(
++	SSL *s,
++	int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++				     STACK_OF(SSL_CIPHER) *peer_ciphers,
++				     SSL_CIPHER **cipher, void *arg), void *arg)
++{
++    if (s == NULL)
++	    return 0;
++    s->tls_session_secret_cb = tls_session_secret_cb;
++    s->tls_session_secret_cb_arg = arg;
++    return 1;
++}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg)
++{
++    if (s == NULL)
++	    return 0;
++    s->tls_session_ticket_ext_cb = cb;
++    s->tls_session_ticket_ext_cb_arg = arg;
++    return 1;
++}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++{
++    if (s->version >= TLS1_VERSION) {
++	if (s->tlsext_session_ticket) {
++	    OPENSSL_free(s->tlsext_session_ticket);
++	    s->tlsext_session_ticket = NULL;
++	}
++
++	s->tlsext_session_ticket = OPENSSL_malloc(
++		sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++	if (!s->tlsext_session_ticket) {
++	    SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++	    return 0;
++	}
++
++	if (ext_data) {
++	    s->tlsext_session_ticket->length = ext_len;
++	    s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++	    memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++	} else {
++		s->tlsext_session_ticket->length = 0;
++		s->tlsext_session_ticket->data = NULL;
++	}
++
++	return 1;
++    }
++
++    return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st {
+     SSL_CTX *ctx;
+     long time;
+diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
+--- openssl-0.9.8zf.orig/ssl/t1_lib.c	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/t1_lib.c	2015-03-24 16:32:46.923905254 +0200
+@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ {
++#ifndef OPENSSL_NO_TLSEXT
++    if (s->tlsext_session_ticket) {
++	OPENSSL_free(s->tlsext_session_ticket);
++    }
++#endif
+     ssl3_free(s);
+ }
+ 
+@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
+         int ticklen;
+         if (!s->new_session && s->session && s->session->tlsext_tick)
+             ticklen = s->session->tlsext_ticklen;
+-        else
++	else if (s->session && s->tlsext_session_ticket &&
++		 s->tlsext_session_ticket->data) {
++	    ticklen = s->tlsext_session_ticket->length;
++	    s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++	    if (!s->session->tlsext_tick)
++		return NULL;
++	    memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
++		   ticklen);
++	    s->session->tlsext_ticklen = ticklen;
++	} else
+             ticklen = 0;
++	if (ticklen == 0 && s->tlsext_session_ticket &&
++	    s->tlsext_session_ticket->data == NULL)
++	    goto skip_ext;
+         /*
+          * Check for enough room 2 for extension type, 2 for len rest for
+          * ticket
+@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
+             ret += ticklen;
+         }
+     }
++skip_ext:
+ 
+     if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+         s->version != DTLS1_VERSION) {
+@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+             if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+                 return 0;
+             renegotiate_seen = 1;
++	} else if (type == TLSEXT_TYPE_session_ticket) {
++	    if (s->tls_session_ticket_ext_cb &&
++		!s->tls_session_ticket_ext_cb(s, data, size,
++					      s->tls_session_ticket_ext_cb_arg))
++	    {
++		*al = TLS1_AD_INTERNAL_ERROR;
++		return 0;
++	    }
+         } else if (type == TLSEXT_TYPE_status_request &&
+                    s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
+ 
+@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+             }
+             tlsext_servername = 1;
+         } else if (type == TLSEXT_TYPE_session_ticket) {
++	    if (s->tls_session_ticket_ext_cb &&
++		!s->tls_session_ticket_ext_cb(
++			s, data, size,
++			s->tls_session_ticket_ext_cb_arg)) {
++		*al = TLS1_AD_INTERNAL_ERROR;
++		return 0;
++	    }
+             if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+                 || (size > 0)) {
+                 *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
+                 s->tlsext_ticket_expected = 1;
+                 return 0;       /* Cache miss */
+             }
++	    if (s->tls_session_secret_cb) {
++		/* Indicate cache miss here and instead of
++		 * generating the session from ticket now,
++		 * trigger abbreviated handshake based on
++		 * external mechanism to calculate the master
++		 * secret later. */
++		return 0;
++	    }
+             return tls_decrypt_ticket(s, p, size, session_id, len, ret);
+         }
+         p += size;
+diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
+--- openssl-0.9.8zf.orig/ssl/tls1.h	2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/tls1.h	2015-03-24 16:33:31.855904894 +0200
+@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #  define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
+ # endif
+ 
++/* TLS extension struct */
++struct tls_session_ticket_ext_st {
++    unsigned short length;
++    void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
+--- openssl-0.9.8zf.orig/util/ssleay.num	2015-03-19 15:47:15.000000000 +0200
++++ openssl-0.9.8zf/util/ssleay.num	2015-03-24 16:33:51.127904739 +0200
+@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
+ SSL_CTX_set_client_cert_engine          293	EXIST::FUNCTION:ENGINE
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	EXIST::FUNCTION:TLSEXT
diff --git a/src/ap/Makefile b/src/ap/Makefile
index adfd3df..98788fe 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,8 +1,67 @@
-all:
-	@echo Nothing to be made.
+all: libap.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DHOSTAPD
+CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_WPS
+CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IAPP
+
+LIB_OBJS= \
+	accounting.o \
+	ap_config.o \
+	ap_drv_ops.o \
+	ap_list.o \
+	ap_mlme.o \
+	authsrv.o \
+	beacon.o \
+	bss_load.o \
+	ctrl_iface_ap.o \
+	dfs.o \
+	dhcp_snoop.o \
+	drv_callbacks.o \
+	eap_user_db.o \
+	gas_serv.o \
+	hostapd.o \
+	hs20.o \
+	hw_features.o \
+	iapp.o \
+	ieee802_11_auth.o \
+	ieee802_11.o \
+	ieee802_11_ht.o \
+	ieee802_11_shared.o \
+	ieee802_11_vht.o \
+	ieee802_1x.o \
+	ndisc_snoop.o \
+	p2p_hostapd.o \
+	peerkey_auth.o \
+	pmksa_cache_auth.o \
+	preauth_auth.o \
+	sta_info.o \
+	tkip_countermeasures.o \
+	utils.o \
+	vlan_init.o \
+	wmm.o \
+	wnm_ap.o \
+	wpa_auth.o \
+	wpa_auth_ft.o \
+	wpa_auth_glue.o \
+	wpa_auth_ie.o \
+	wps_hostapd.o \
+	x_snoop.o
+
+libap.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 97cf26f..652d020 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -242,6 +242,7 @@
 
 
 static int acs_request_scan(struct hostapd_iface *iface);
+static int acs_survey_is_sufficient(struct freq_survey *survey);
 
 
 static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@@ -328,6 +329,7 @@
 	struct freq_survey *survey;
 	unsigned int i = 0;
 	long double int_factor = 0;
+	unsigned count = 0;
 
 	if (dl_list_empty(&chan->survey_list))
 		return;
@@ -339,18 +341,27 @@
 
 	dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
 	{
+		i++;
+
+		if (!acs_survey_is_sufficient(survey)) {
+			wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i);
+			continue;
+		}
+
+		count++;
 		int_factor = acs_survey_interference_factor(survey,
 							    iface->lowest_nf);
 		chan->interference_factor += int_factor;
 		wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu",
-			   ++i, chan->min_nf, int_factor,
+			   i, chan->min_nf, int_factor,
 			   survey->nf, (unsigned long) survey->channel_time,
 			   (unsigned long) survey->channel_time_busy,
 			   (unsigned long) survey->channel_time_rx);
 	}
 
-	chan->interference_factor = chan->interference_factor /
-		dl_list_len(&chan->survey_list);
+	if (!count)
+		return;
+	chan->interference_factor /= count;
 }
 
 
@@ -384,18 +395,19 @@
 static int acs_survey_is_sufficient(struct freq_survey *survey)
 {
 	if (!(survey->filled & SURVEY_HAS_NF)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor");
+		wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
 		return 0;
 	}
 
 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time");
+		wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
 		return 0;
 	}
 
 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
 	    !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
-		wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)");
+		wpa_printf(MSG_INFO,
+			   "ACS: Survey is missing RX and busy time (at least one is required)");
 		return 0;
 	}
 
@@ -406,18 +418,27 @@
 static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
 {
 	struct freq_survey *survey;
+	int ret = -1;
 
 	dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
 	{
-		if (!acs_survey_is_sufficient(survey)) {
-			wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data",
-				   chan->chan);
-			return 0;
+		if (acs_survey_is_sufficient(survey)) {
+			ret = 1;
+			break;
 		}
+		ret = 0;
 	}
 
-	return 1;
+	if (ret == -1)
+		ret = 1; /* no survey list entries */
 
+	if (!ret) {
+		wpa_printf(MSG_INFO,
+			   "ACS: Channel %d has insufficient survey data",
+			   chan->chan);
+	}
+
+	return ret;
 }
 
 
@@ -455,6 +476,16 @@
 }
 
 
+static int is_in_chanlist(struct hostapd_iface *iface,
+			  struct hostapd_channel_data *chan)
+{
+	if (!iface->conf->acs_ch_list.num)
+		return 1;
+
+	return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
+}
+
+
 static void acs_survey_all_chans_intereference_factor(
 	struct hostapd_iface *iface)
 {
@@ -467,6 +498,9 @@
 		if (!acs_usable_chan(chan))
 			continue;
 
+		if (!is_in_chanlist(iface, chan))
+			continue;
+
 		wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
 			   chan->chan, chan->freq);
 
@@ -498,6 +532,36 @@
 }
 
 
+static int is_24ghz_mode(enum hostapd_hw_mode mode)
+{
+	return mode == HOSTAPD_MODE_IEEE80211B ||
+		mode == HOSTAPD_MODE_IEEE80211G;
+}
+
+
+static int is_common_24ghz_chan(int chan)
+{
+	return chan == 1 || chan == 6 || chan == 11;
+}
+
+
+#ifndef ACS_ADJ_WEIGHT
+#define ACS_ADJ_WEIGHT 0.85
+#endif /* ACS_ADJ_WEIGHT */
+
+#ifndef ACS_NEXT_ADJ_WEIGHT
+#define ACS_NEXT_ADJ_WEIGHT 0.55
+#endif /* ACS_NEXT_ADJ_WEIGHT */
+
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 by default even if a neighboring
+ * channel has a smaller interference factor as long as it is not better by more
+ * than this multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
 /*
  * At this point it's assumed chan->interface_factor has been computed.
  * This function should be reusable regardless of interference computation
@@ -512,6 +576,7 @@
 	long double factor, ideal_factor = 0;
 	int i, j;
 	int n_chans = 1;
+	unsigned int k;
 
 	/* TODO: HT40- support */
 
@@ -538,11 +603,16 @@
 		   -1);
 
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		double total_weight;
+		struct acs_bias *bias, tmp_bias;
+
 		chan = &iface->current_mode->channels[i];
 
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
+		if (!is_in_chanlist(iface, chan))
+			continue;
 
 		/* HT40 on 5 GHz has a limited set of primary channels as per
 		 * 11n Annex J */
@@ -567,14 +637,17 @@
 		factor = 0;
 		if (acs_usable_chan(chan))
 			factor = chan->interference_factor;
+		total_weight = 1;
 
 		for (j = 1; j < n_chans; j++) {
 			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
 			if (!adj_chan)
 				break;
 
-			if (acs_usable_chan(adj_chan))
+			if (acs_usable_chan(adj_chan)) {
 				factor += adj_chan->interference_factor;
+				total_weight += 1;
+			}
 		}
 
 		if (j != n_chans) {
@@ -585,36 +658,69 @@
 
 		/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
 		 * channel interference factor. */
-		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
-		    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) {
+		if (is_24ghz_mode(iface->current_mode->mode)) {
 			for (j = 0; j < n_chans; j++) {
-				/* TODO: perhaps a multiplier should be used
-				 * here? */
-
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 			}
 		}
 
-		wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
-			   chan->chan, factor);
+		factor /= total_weight;
+
+		bias = NULL;
+		if (iface->conf->acs_chan_bias) {
+			for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
+				bias = &iface->conf->acs_chan_bias[k];
+				if (bias->channel == chan->chan)
+					break;
+				bias = NULL;
+			}
+		} else if (is_24ghz_mode(iface->current_mode->mode) &&
+			   is_common_24ghz_chan(chan->chan)) {
+			tmp_bias.channel = chan->chan;
+			tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
+			bias = &tmp_bias;
+		}
+
+		if (bias) {
+			factor *= bias->bias;
+			wpa_printf(MSG_DEBUG,
+				   "ACS:  * channel %d: total interference = %Lg (%f bias)",
+				   chan->chan, factor, bias->bias);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "ACS:  * channel %d: total interference = %Lg",
+				   chan->chan, factor);
+		}
 
 		if (acs_usable_chan(chan) &&
 		    (!ideal_chan || factor < ideal_factor)) {
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5bc468a..cccbfab 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -181,6 +181,8 @@
 	conf->corrupt_gtk_rekey_mic_probability = 0.0;
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	conf->acs = 0;
+	conf->acs_ch_list.num = 0;
 #ifdef CONFIG_ACS
 	conf->acs_num_scans = 5;
 #endif /* CONFIG_ACS */
@@ -394,20 +396,27 @@
 }
 
 
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
+{
+	struct hostapd_wpa_psk *psk, *tmp;
+
+	for (psk = *l; psk;) {
+		tmp = psk;
+		psk = psk->next;
+		bin_clear_free(tmp, sizeof(*tmp));
+	}
+	*l = NULL;
+}
+
+
 void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
-	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
 
 	if (conf == NULL)
 		return;
 
-	psk = conf->ssid.wpa_psk;
-	while (psk) {
-		prev = psk;
-		psk = psk->next;
-		bin_clear_free(prev, sizeof(*prev));
-	}
+	hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
 
 	str_clear_free(conf->ssid.wpa_passphrase);
 	os_free(conf->ssid.wpa_psk_file);
@@ -496,6 +505,12 @@
 	os_free(conf->model_description);
 	os_free(conf->model_url);
 	os_free(conf->upc);
+	{
+		unsigned int i;
+
+		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+			wpabuf_free(conf->wps_vendor_ext[i]);
+	}
 	wpabuf_free(conf->wps_nfc_dh_pubkey);
 	wpabuf_free(conf->wps_nfc_dh_privkey);
 	wpabuf_free(conf->wps_nfc_dev_pw);
@@ -566,8 +581,11 @@
 	os_free(conf->bss);
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
-	os_free(conf->chanlist);
+	os_free(conf->acs_ch_list.range);
 	os_free(conf->driver_params);
+#ifdef CONFIG_ACS
+	os_free(conf->acs_chan_bias);
+#endif /* CONFIG_ACS */
 
 	os_free(conf);
 }
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ce8ac9b..00848ba 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_defs.h"
 #include "common/ieee802_11_common.h"
 #include "wps/wps.h"
 
@@ -57,8 +58,6 @@
 struct ft_remote_r0kh;
 struct ft_remote_r1kh;
 
-#define HOSTAPD_MAX_SSID_LEN 32
-
 #define NUM_WEP_KEYS 4
 struct hostapd_wep_keys {
 	u8 idx;
@@ -78,7 +77,7 @@
 } secpolicy;
 
 struct hostapd_ssid {
-	u8 ssid[HOSTAPD_MAX_SSID_LEN];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
@@ -114,6 +113,7 @@
 	struct hostapd_vlan *next;
 	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
 	char ifname[IFNAMSIZ + 1];
+	int configured;
 	int dynamic_vlan;
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 
@@ -510,7 +510,7 @@
 		char file[256];
 	} *hs20_icons;
 	size_t hs20_icons_count;
-	u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
+	u8 osu_ssid[SSID_MAX_LEN];
 	size_t osu_ssid_len;
 	struct hs20_osu_provider {
 		unsigned int friendly_name_count;
@@ -551,6 +551,9 @@
 	int mesh;
 
 	int radio_measurements;
+
+	int vendor_vht;
+
 	char *neighbor_ap_list_file;
 };
 
@@ -567,7 +570,8 @@
 	int fragm_threshold;
 	u8 send_probe_response;
 	u8 channel;
-	int *chanlist;
+	u8 acs;
+	struct wpa_freq_range_list acs_ch_list;
 	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
 	enum {
 		LONG_PREAMBLE = 0,
@@ -628,6 +632,10 @@
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
 
+#ifdef CONFIG_P2P
+	u8 p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	double ignore_probe_probability;
 	double ignore_auth_probability;
@@ -638,6 +646,11 @@
 
 #ifdef CONFIG_ACS
 	unsigned int acs_num_scans;
+	struct acs_bias {
+		int channel;
+		double bias;
+	} *acs_chan_bias;
+	unsigned int num_acs_chan_bias;
 #endif /* CONFIG_ACS */
 };
 
@@ -647,6 +660,7 @@
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
 void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
 void hostapd_config_free_bss(struct hostapd_bss_config *conf);
 void hostapd_config_free(struct hostapd_config *conf);
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 7486fda..9ee88b4 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "wps/wps.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -216,6 +217,15 @@
 }
 
 
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
+}
+
+
 int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
 {
 	struct wpabuf *beacon, *proberesp, *assocresp;
@@ -477,93 +487,8 @@
 }
 
 
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
-			    int freq, int channel, int ht_enabled,
-			    int vht_enabled, int sec_channel_offset,
-			    int vht_oper_chwidth, int center_segment0,
-			    int center_segment1, u32 vht_caps)
-{
-	int tmp;
-
-	os_memset(data, 0, sizeof(*data));
-	data->mode = mode;
-	data->freq = freq;
-	data->channel = channel;
-	data->ht_enabled = ht_enabled;
-	data->vht_enabled = vht_enabled;
-	data->sec_channel_offset = sec_channel_offset;
-	data->center_freq1 = freq + sec_channel_offset * 10;
-	data->center_freq2 = 0;
-	data->bandwidth = sec_channel_offset ? 40 : 20;
-
-	/*
-	 * This validation code is probably misplaced, maybe it should be
-	 * in src/ap/hw_features.c and check the hardware support as well.
-	 */
-	if (data->vht_enabled) switch (vht_oper_chwidth) {
-	case VHT_CHANWIDTH_USE_HT:
-		if (center_segment1)
-			return -1;
-		if (center_segment0 != 0 &&
-		    5000 + center_segment0 * 5 != data->center_freq1 &&
-		    2407 + center_segment0 * 5 != data->center_freq1)
-			return -1;
-		break;
-	case VHT_CHANWIDTH_80P80MHZ:
-		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
-			wpa_printf(MSG_ERROR,
-				   "80+80 channel width is not supported!");
-			return -1;
-		}
-		if (center_segment1 == center_segment0 + 4 ||
-		    center_segment1 == center_segment0 - 4)
-			return -1;
-		data->center_freq2 = 5000 + center_segment1 * 5;
-		/* fall through */
-	case VHT_CHANWIDTH_80MHZ:
-		data->bandwidth = 80;
-		if (vht_oper_chwidth == 1 && center_segment1)
-			return -1;
-		if (vht_oper_chwidth == 3 && !center_segment1)
-			return -1;
-		if (!sec_channel_offset)
-			return -1;
-		/* primary 40 part must match the HT configuration */
-		tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
-		tmp /= 2;
-		if (data->center_freq1 != 5000 +
-					 center_segment0 * 5 - 20 + 40 * tmp)
-			return -1;
-		data->center_freq1 = 5000 + center_segment0 * 5;
-		break;
-	case VHT_CHANWIDTH_160MHZ:
-		data->bandwidth = 160;
-		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
-				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
-			wpa_printf(MSG_ERROR,
-				   "160MHZ channel width is not supported!");
-			return -1;
-		}
-		if (center_segment1)
-			return -1;
-		if (!sec_channel_offset)
-			return -1;
-		/* primary 40 part must match the HT configuration */
-		tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
-		tmp /= 2;
-		if (data->center_freq1 != 5000 +
-					 center_segment0 * 5 - 60 + 40 * tmp)
-			return -1;
-		data->center_freq1 = 5000 + center_segment0 * 5;
-		break;
-	}
-
-	return 0;
-}
-
-
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+		     int freq, int channel, int ht_enabled, int vht_enabled,
 		     int sec_channel_offset, int vht_oper_chwidth,
 		     int center_segment0, int center_segment1)
 {
@@ -748,7 +673,8 @@
 }
 
 
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+			  enum hostapd_hw_mode mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1)
@@ -798,13 +724,66 @@
 int hostapd_drv_do_acs(struct hostapd_data *hapd)
 {
 	struct drv_acs_params params;
+	int ret, i, acs_ch_list_all = 0;
+	u8 *channels = NULL;
+	unsigned int num_channels = 0;
+	struct hostapd_hw_modes *mode;
 
 	if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
 		return 0;
+
 	os_memset(&params, 0, sizeof(params));
 	params.hw_mode = hapd->iface->conf->hw_mode;
+
+	/*
+	 * If no chanlist config parameter is provided, include all enabled
+	 * channels of the selected hw_mode.
+	 */
+	if (!hapd->iface->conf->acs_ch_list.num)
+		acs_ch_list_all = 1;
+
+	mode = hapd->iface->current_mode;
+	if (mode == NULL)
+		return -1;
+	channels = os_malloc(mode->num_channels);
+	if (channels == NULL)
+		return -1;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (!acs_ch_list_all &&
+		    !freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
+					      chan->chan))
+			continue;
+		if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+			channels[num_channels++] = chan->chan;
+	}
+
+	params.ch_list = channels;
+	params.ch_list_len = num_channels;
+
 	params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
 	params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
 				 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
-	return hapd->driver->do_acs(hapd->drv_priv, &params);
+	params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+	params.ch_width = 20;
+	if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
+		params.ch_width = 40;
+
+	/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+	 */
+	if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
+		if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+			params.ch_width = 80;
+		else if (hapd->iface->conf->vht_oper_chwidth ==
+			 VHT_CHANWIDTH_160MHZ ||
+			 hapd->iface->conf->vht_oper_chwidth ==
+			 VHT_CHANWIDTH_80P80MHZ)
+			params.ch_width = 160;
+	}
+
+	ret = hapd->driver->do_acs(hapd->drv_priv, &params);
+	os_free(channels);
+
+	return ret;
 }
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 7ad3ed7..82eaf3f 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -24,6 +24,7 @@
 void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
 			       struct wpabuf *proberesp,
 			       struct wpabuf *assocresp);
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
 int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
 int hostapd_set_authorized(struct hostapd_data *hapd,
 			   struct sta_info *sta, int authorized);
@@ -57,8 +58,8 @@
 int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
 		       const u8 *addr, int idx, u8 *seq);
 int hostapd_flush(struct hostapd_data *hapd);
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+		     int freq, int channel, int ht_enabled, int vht_enabled,
 		     int sec_channel_offset, int vht_oper_chwidth,
 		     int center_segment0, int center_segment1);
 int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@@ -102,15 +103,11 @@
 		      int reassoc, u16 status, const u8 *ie, size_t len);
 int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
 		      u8 *tspec_ie, size_t tspec_ielen);
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+			  enum hostapd_hw_mode mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1);
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
-			    int freq, int channel, int ht_enabled,
-			    int vht_enabled, int sec_channel_offset,
-			    int vht_oper_chwidth, int center_segment0,
-			    int center_segment1, u32 vht_caps);
 int hostapd_drv_do_acs(struct hostapd_data *hapd);
 
 
@@ -333,4 +330,11 @@
 					data_len, buf);
 }
 
+static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+		return 0;
+	return hapd->driver->stop_ap(hapd->drv_priv);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index d4fec5b..2f007c5 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -111,8 +111,8 @@
 	if (s->hnext != NULL)
 		s->hnext = s->hnext->hnext;
 	else
-		printf("AP: could not remove AP " MACSTR " from hash table\n",
-		       MAC2STR(ap->addr));
+		wpa_printf(MSG_INFO, "AP: could not remove AP " MACSTR
+			   " from hash table",  MAC2STR(ap->addr));
 }
 
 
@@ -182,7 +182,8 @@
 	if (!ap) {
 		ap = ap_ap_add(iface, mgmt->bssid);
 		if (!ap) {
-			printf("Failed to allocate AP information entry\n");
+			wpa_printf(MSG_INFO,
+				   "Failed to allocate AP information entry");
 			return;
 		}
 		new_ap = 1;
@@ -192,14 +193,14 @@
 			  elems->supp_rates, elems->supp_rates_len,
 			  elems->ext_supp_rates, elems->ext_supp_rates_len);
 
-	if (elems->erp_info && elems->erp_info_len == 1)
+	if (elems->erp_info)
 		ap->erp = elems->erp_info[0];
 	else
 		ap->erp = -1;
 
-	if (elems->ds_params && elems->ds_params_len == 1)
+	if (elems->ds_params)
 		ap->channel = elems->ds_params[0];
-	else if (elems->ht_operation && elems->ht_operation_len >= 1)
+	else if (elems->ht_operation)
 		ap->channel = elems->ht_operation[0];
 	else if (fi)
 		ap->channel = fi->channel;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index bd1778e..f10e1b7 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -55,10 +55,11 @@
 {
 	const struct hostapd_eap_user *eap_user;
 	int i;
+	int rv = -1;
 
 	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
 	if (eap_user == NULL)
-		return -1;
+		goto out;
 
 	if (user == NULL)
 		return 0;
@@ -72,7 +73,7 @@
 	if (eap_user->password) {
 		user->password = os_malloc(eap_user->password_len);
 		if (user->password == NULL)
-			return -1;
+			goto out;
 		os_memcpy(user->password, eap_user->password,
 			  eap_user->password_len);
 		user->password_len = eap_user->password_len;
@@ -83,8 +84,13 @@
 	user->ttls_auth = eap_user->ttls_auth;
 	user->remediation = eap_user->remediation;
 	user->accept_attr = eap_user->accept_attr;
+	rv = 0;
 
-	return 0;
+out:
+	if (rv)
+		wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+	return rv;
 }
 
 
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 82fd7c4..1a46d4d 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -15,6 +15,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/hw_features_common.h"
 #include "wps/wps_defs.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -363,7 +364,6 @@
 
 
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
-				   struct sta_info *sta,
 				   const struct ieee80211_mgmt *req,
 				   int is_p2p, size_t *resp_len)
 {
@@ -383,6 +383,10 @@
 #endif /* CONFIG_P2P */
 	if (hapd->conf->vendor_elements)
 		buflen += wpabuf_len(hapd->conf->vendor_elements);
+	if (hapd->conf->vendor_vht) {
+		buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+			2 + sizeof(struct ieee80211_vht_operation);
+	}
 	resp = os_zalloc(buflen);
 	if (resp == NULL)
 		return NULL;
@@ -401,7 +405,7 @@
 
 	/* hardware or low-level driver will setup seq_ctrl and timestamp */
 	resp->u.probe_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+		host_to_le16(hostapd_own_capab_info(hapd));
 
 	pos = resp->u.probe_resp.variable;
 	*pos++ = WLAN_EID_SSID;
@@ -450,8 +454,12 @@
 	pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
 				    &hapd->cs_c_off_proberesp);
 #ifdef CONFIG_IEEE80211AC
-	pos = hostapd_eid_vht_capabilities(hapd, pos);
-	pos = hostapd_eid_vht_operation(hapd, pos);
+	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+		pos = hostapd_eid_vht_capabilities(hapd, pos);
+		pos = hostapd_eid_vht_operation(hapd, pos);
+	}
+	if (hapd->conf->vendor_vht)
+		pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
 	/* Wi-Fi Alliance WMM */
@@ -543,7 +551,6 @@
 	struct ieee802_11_elems elems;
 	const u8 *ie;
 	size_t ie_len;
-	struct sta_info *sta = NULL;
 	size_t i, resp_len;
 	int noack;
 	enum ssid_match_result res;
@@ -579,6 +586,27 @@
 		return;
 	}
 
+	/*
+	 * No need to reply if the Probe Request frame was sent on an adjacent
+	 * channel. IEEE Std 802.11-2012 describes this as a requirement for an
+	 * AP with dot11RadioMeasurementActivated set to true, but strictly
+	 * speaking does not allow such ignoring of Probe Request frames if
+	 * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
+	 * number of unnecessary Probe Response frames for cases where the STA
+	 * is less likely to see them (Probe Request frame sent on a
+	 * neighboring, but partially overlapping, channel).
+	 */
+	if (elems.ds_params &&
+	    hapd->iface->current_mode &&
+	    (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
+	     hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
+	    hapd->iconf->channel != elems.ds_params[0]) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
+			   hapd->iconf->channel, elems.ds_params[0]);
+		return;
+	}
+
 #ifdef CONFIG_P2P
 	if (hapd->p2p && elems.wps_ie) {
 		struct wpabuf *wps;
@@ -613,8 +641,6 @@
 		return;
 	}
 
-	sta = ap_get_sta(hapd, mgmt->sa);
-
 #ifdef CONFIG_P2P
 	if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
 	    elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
@@ -634,10 +660,7 @@
 
 	res = ssid_match(hapd, elems.ssid, elems.ssid_len,
 			 elems.ssid_list, elems.ssid_list_len);
-	if (res != NO_SSID_MATCH) {
-		if (sta)
-			sta->ssid_probe = &hapd->conf->ssid;
-	} else {
+	if (res == NO_SSID_MATCH) {
 		if (!(mgmt->da[0] & 0x01)) {
 			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
 				   " for foreign SSID '%s' (DA " MACSTR ")%s",
@@ -704,7 +727,7 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
-	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+	resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
 				      &resp_len);
 	if (resp == NULL)
 		return;
@@ -759,7 +782,7 @@
 			   "this");
 
 	/* Generate a Probe Response template for the non-P2P case */
-	return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
 }
 
 #endif /* NEED_AP_MLME */
@@ -791,6 +814,14 @@
 #endif /* CONFIG_P2P */
 	if (hapd->conf->vendor_elements)
 		tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+	if (hapd->conf->vendor_vht) {
+		tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+			2 + sizeof(struct ieee80211_vht_operation);
+	}
+#endif /* CONFIG_IEEE80211AC */
+
 	tailpos = tail = os_malloc(tail_len);
 	if (head == NULL || tail == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -810,7 +841,7 @@
 		host_to_le16(hapd->iconf->beacon_int);
 
 	/* hardware or low-level driver will setup seq_ctrl and timestamp */
-	capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+	capab_info = hostapd_own_capab_info(hapd);
 	head->u.beacon.capab_info = host_to_le16(capab_info);
 	pos = &head->u.beacon.variable[0];
 
@@ -880,8 +911,12 @@
 	tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
 					&hapd->cs_c_off_beacon);
 #ifdef CONFIG_IEEE80211AC
-	tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
-	tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+		tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+		tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+	}
+	if (hapd->conf->vendor_vht)
+		tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
 	/* Wi-Fi Alliance WMM */
@@ -981,6 +1016,9 @@
 		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_P2P
+	params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
 #ifdef CONFIG_HS20
 	params->disable_dgaf = hapd->conf->disable_dgaf;
 	if (hapd->conf->osen) {
@@ -1029,6 +1067,8 @@
 	params.beacon_ies = beacon;
 	params.proberesp_ies = proberesp;
 	params.assocresp_ies = assocresp;
+	params.reenable = hapd->reenable_beacon;
+	hapd->reenable_beacon = 0;
 
 	if (iface->current_mode &&
 	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 8c84e3e..41ab988 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -537,3 +537,9 @@
 
 	return 0;
 }
+
+
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
+{
+	return hostapd_drv_stop_ap(hapd);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index ee58b4c..e5297d0 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -23,6 +23,6 @@
 			      size_t buflen);
 int hostapd_parse_csa_settings(const char *pos,
 			       struct csa_settings *settings);
-
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
 
 #endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0db5ef6..715f19b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1,7 +1,7 @@
 /*
  * DFS - Dynamic Frequency Selection
  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
@@ -121,6 +122,20 @@
 }
 
 
+static struct hostapd_channel_data *
+dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
+{
+	int i;
+
+	for (i = first_chan_idx; i < mode->num_channels; i++) {
+		if (mode->channels[i].freq == freq)
+			return &mode->channels[i];
+	}
+
+	return NULL;
+}
+
+
 static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
 				    int first_chan_idx, int num_chans,
 				    int skip_radar)
@@ -128,15 +143,15 @@
 	struct hostapd_channel_data *first_chan, *chan;
 	int i;
 
-	if (first_chan_idx + num_chans >= mode->num_channels)
+	if (first_chan_idx + num_chans > mode->num_channels)
 		return 0;
 
 	first_chan = &mode->channels[first_chan_idx];
 
 	for (i = 0; i < num_chans; i++) {
-		chan = &mode->channels[first_chan_idx + i];
-
-		if (first_chan->freq + i * 20 != chan->freq)
+		chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
+					 first_chan_idx);
+		if (!chan)
 			return 0;
 
 		if (!dfs_channel_available(chan, skip_radar))
@@ -150,16 +165,10 @@
 static int is_in_chanlist(struct hostapd_iface *iface,
 			  struct hostapd_channel_data *chan)
 {
-	int *entry;
-
-	if (!iface->conf->chanlist)
+	if (!iface->conf->acs_ch_list.num)
 		return 1;
 
-	for (entry = iface->conf->chanlist; *entry != -1; entry++) {
-		if (*entry == chan->chan)
-			return 1;
-	}
-	return 0;
+	return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
 }
 
 
@@ -747,11 +756,19 @@
 
 	if (success) {
 		/* Complete iface/ap configuration */
-		set_dfs_state(iface, freq, ht_enabled, chan_offset,
-			      chan_width, cf1, cf2,
-			      HOSTAPD_CHAN_DFS_AVAILABLE);
-		iface->cac_started = 0;
-		hostapd_setup_interface_complete(iface, 0);
+		if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+			/* Complete AP configuration for the first bring up. */
+			if (iface->state != HAPD_IFACE_ENABLED)
+				hostapd_setup_interface_complete(iface, 0);
+			else
+				iface->cac_started = 0;
+		} else {
+			set_dfs_state(iface, freq, ht_enabled, chan_offset,
+				      chan_width, cf1, cf2,
+				      HOSTAPD_CHAN_DFS_AVAILABLE);
+			iface->cac_started = 0;
+			hostapd_setup_interface_complete(iface, 0);
+		}
 	}
 
 	return 0;
@@ -933,13 +950,17 @@
 {
 	int res;
 
-	if (!iface->conf->ieee80211h)
-		return 0;
-
 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
 
+	/* Proceed only if DFS is not offloaded to the driver */
+	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+		return 0;
+
+	if (!iface->conf->ieee80211h)
+		return 0;
+
 	/* mark radar frequency as invalid */
 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
 		      cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
@@ -963,6 +984,11 @@
 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+	/* Proceed only if DFS is not offloaded to the driver */
+	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+		return 0;
+
 	/* TODO add correct implementation here */
 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
@@ -994,3 +1020,53 @@
 		res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
 	return res;
 }
+
+
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+			  int ht_enabled, int chan_offset, int chan_width,
+			  int cf1, int cf2)
+{
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+		"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
+		"seg1=%d cac_time=%ds",
+		freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+	iface->cac_started = 1;
+	return 0;
+}
+
+
+/*
+ * Main DFS handler for offloaded case.
+ * 2 - continue channel/AP setup for non-DFS channel
+ * 1 - continue channel/AP setup for DFS channel
+ * 0 - channel/AP setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
+{
+	wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+		   __func__, iface->cac_started);
+
+	/*
+	 * If DFS has already been started, then we are being called from a
+	 * callback to continue AP/channel setup. Reset the CAC start flag and
+	 * return.
+	 */
+	if (iface->cac_started) {
+		wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+			   __func__, iface->cac_started);
+		iface->cac_started = 0;
+		return 1;
+	}
+
+	if (ieee80211_is_dfs(iface->freq)) {
+		wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
+			   __func__, iface->freq);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
+		   __func__, iface->freq);
+	return 2;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index a619c55..be8c0e6 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -22,5 +22,9 @@
 			     int ht_enabled,
 			     int chan_offset, int chan_width, int cf1, int cf2);
 int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+			  int ht_enabled, int chan_offset, int chan_width,
+			  int cf1, int cf2);
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
 
 #endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index a706024..3a77225 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -42,6 +42,17 @@
 static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
 
 
+static const char * ipaddr_str(u32 addr)
+{
+	static char buf[17];
+
+	os_snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
+		    (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+		    (addr >> 8) & 0xff, addr & 0xff);
+	return buf;
+}
+
+
 static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
 			size_t len)
 {
@@ -109,16 +120,17 @@
 			return;
 
 		wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
-			   " @ IPv4 address %X/%d",
-			   MAC2STR(sta->addr), ntohl(b->your_ip), prefixlen);
+			   " @ IPv4 address %s/%d",
+			   MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+			   prefixlen);
 
 		if (sta->ipaddr == b->your_ip)
 			return;
 
 		if (sta->ipaddr != 0) {
 			wpa_printf(MSG_DEBUG,
-				   "dhcp_snoop: Removing IPv4 address %X from the ip neigh table",
-				   sta->ipaddr);
+				   "dhcp_snoop: Removing IPv4 address %s from the ip neigh table",
+				   ipaddr_str(be_to_host32(sta->ipaddr)));
 			hostapd_drv_br_delete_ip_neigh(hapd, 4,
 						       (u8 *) &sta->ipaddr);
 		}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 016f5ed..55f429a 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -128,8 +128,6 @@
 #ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
 	if (elems.ht_capabilities &&
-	    elems.ht_capabilities_len >=
-	    sizeof(struct ieee80211_ht_capabilities) &&
 	    (hapd->iface->conf->ht_capab &
 	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
 		struct ieee80211_ht_capabilities *ht_cap =
@@ -441,7 +439,7 @@
 			     int offset, int width, int cf1, int cf2)
 {
 #ifdef NEED_AP_MLME
-	int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
+	int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO,
@@ -499,13 +497,18 @@
 	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
 	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
 
+	is_dfs = ieee80211_is_dfs(freq);
+
 	if (hapd->csa_in_progress &&
 	    freq == hapd->cs_freq_params.freq) {
 		hostapd_cleanup_cs_params(hapd);
 		ieee802_11_set_beacon(hapd);
 
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
-			freq);
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+			"freq=%d dfs=%d", freq, is_dfs);
+	} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+			"freq=%d dfs=%d", freq, is_dfs);
 	}
 #endif /* NEED_AP_MLME */
 }
@@ -529,9 +532,8 @@
 
 #ifdef CONFIG_ACS
 static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
-					 u8 pri_channel, u8 sec_channel)
+					 struct acs_selected_channels *acs_res)
 {
-	int channel;
 	int ret;
 
 	if (hapd->iconf->channel) {
@@ -540,29 +542,55 @@
 		return;
 	}
 
-	hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+	hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
 
-	channel = pri_channel;
-	if (!channel) {
+	if (!acs_res->pri_channel) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
 			       "driver switched to bad channel");
 		return;
 	}
 
-	hapd->iconf->channel = channel;
+	hapd->iconf->channel = acs_res->pri_channel;
+	hapd->iconf->acs = 1;
 
-	if (sec_channel == 0)
+	if (acs_res->sec_channel == 0)
 		hapd->iconf->secondary_channel = 0;
-	else if (sec_channel < pri_channel)
+	else if (acs_res->sec_channel < acs_res->pri_channel)
 		hapd->iconf->secondary_channel = -1;
-	else if (sec_channel > pri_channel)
+	else if (acs_res->sec_channel > acs_res->pri_channel)
 		hapd->iconf->secondary_channel = 1;
 	else {
 		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
 		return;
 	}
 
+	if (hapd->iface->conf->ieee80211ac) {
+		/* set defaults for backwards compatibility */
+		hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
+		hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
+		hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+		if (acs_res->ch_width == 80) {
+			hapd->iconf->vht_oper_centr_freq_seg0_idx =
+				acs_res->vht_seg0_center_ch;
+			hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+		} else if (acs_res->ch_width == 160) {
+			if (acs_res->vht_seg1_center_ch == 0) {
+				hapd->iconf->vht_oper_centr_freq_seg0_idx =
+					acs_res->vht_seg0_center_ch;
+				hapd->iconf->vht_oper_chwidth =
+					VHT_CHANWIDTH_160MHZ;
+			} else {
+				hapd->iconf->vht_oper_centr_freq_seg0_idx =
+					acs_res->vht_seg0_center_ch;
+				hapd->iconf->vht_oper_centr_freq_seg1_idx =
+					acs_res->vht_seg1_center_ch;
+				hapd->iconf->vht_oper_chwidth =
+					VHT_CHANWIDTH_80P80MHZ;
+			}
+		}
+	}
+
 	ret = hostapd_acs_completed(hapd->iface, 0);
 	if (ret) {
 		wpa_printf(MSG_ERROR,
@@ -1034,6 +1062,16 @@
 				 radar->cf1, radar->cf2);
 }
 
+
+static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
+					  struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
+	hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
+			      radar->chan_offset, radar->chan_width,
+			      radar->cf1, radar->cf2);
+}
+
 #endif /* NEED_AP_MLME */
 
 
@@ -1250,18 +1288,34 @@
 			eloop_terminate();
 		}
 		break;
+	case EVENT_DFS_CAC_STARTED:
+		if (!data)
+			break;
+		hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
+		break;
 #endif /* NEED_AP_MLME */
 	case EVENT_INTERFACE_ENABLED:
 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+		if (hapd->disabled && hapd->started) {
+			hapd->disabled = 0;
+			/*
+			 * Try to re-enable interface if the driver stopped it
+			 * when the interface got disabled.
+			 */
+			wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+			hapd->reenable_beacon = 1;
+			ieee802_11_set_beacon(hapd);
+		}
 		break;
 	case EVENT_INTERFACE_DISABLED:
+		hostapd_free_stas(hapd);
 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+		hapd->disabled = 1;
 		break;
 #ifdef CONFIG_ACS
 	case EVENT_ACS_CHANNEL_SELECTED:
-		hostapd_acs_channel_selected(
-			hapd, data->acs_selected_channels.pri_channel,
-			data->acs_selected_channels.sec_channel);
+		hostapd_acs_channel_selected(hapd,
+					     &data->acs_selected_channels);
 		break;
 #endif /* CONFIG_ACS */
 	default:
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 559d77f..082d0f5 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -138,8 +138,12 @@
 	char id_str[256], cmd[300];
 	size_t i;
 
-	if (identity_len >= sizeof(id_str))
+	if (identity_len >= sizeof(id_str)) {
+		wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
+			   __func__, (int) identity_len,
+			   (int) (sizeof(id_str)));
 		return NULL;
+	}
 	os_memcpy(id_str, identity, identity_len);
 	id_str[identity_len] = '\0';
 	for (i = 0; i < identity_len; i++) {
@@ -182,7 +186,9 @@
 	wpa_printf(MSG_DEBUG, "DB: %s", cmd);
 	if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
 	    SQLITE_OK) {
-		wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+		wpa_printf(MSG_DEBUG,
+			   "DB: Failed to complete SQL operation: %s  db: %s",
+			   sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
 	} else if (hapd->tmp_eap_user.next)
 		user = &hapd->tmp_eap_user;
 
@@ -192,8 +198,10 @@
 		wpa_printf(MSG_DEBUG, "DB: %s", cmd);
 		if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
 				 NULL) != SQLITE_OK) {
-			wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
-				   "operation");
+			wpa_printf(MSG_DEBUG,
+				   "DB: Failed to complete SQL operation: %s  db: %s",
+				   sqlite3_errmsg(db),
+				   hapd->conf->eap_user_sqlite);
 		} else if (hapd->tmp_eap_user.next) {
 			user = &hapd->tmp_eap_user;
 			os_free(user->identity);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 2103747..5abe5ed 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -15,6 +15,8 @@
 #include "radius/radius_client.h"
 #include "radius/radius_das.h"
 #include "eap_server/tncs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
 #include "hostapd.h"
 #include "authsrv.h"
 #include "sta_info.h"
@@ -80,8 +82,7 @@
 		 * Force PSK to be derived again since SSID or passphrase may
 		 * have changed.
 		 */
-		os_free(ssid->wpa_psk);
-		ssid->wpa_psk = NULL;
+		hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
 	}
 	if (hostapd_setup_wpa_psk(hapd->conf)) {
 		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
@@ -178,6 +179,7 @@
 		hapd = iface->bss[j];
 		hapd->iconf = newconf;
 		hapd->iconf->channel = oldconf->channel;
+		hapd->iconf->acs = oldconf->acs;
 		hapd->iconf->secondary_channel = oldconf->secondary_channel;
 		hapd->iconf->ieee80211n = oldconf->ieee80211n;
 		hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
@@ -355,6 +357,11 @@
 static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+	hostapd_stop_setup_timers(iface);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
 	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
@@ -614,51 +621,190 @@
 
 
 static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
-					      struct radius_das_attrs *attr)
+					      struct radius_das_attrs *attr,
+					      int *multi)
 {
-	struct sta_info *sta = NULL;
+	struct sta_info *selected, *sta;
 	char buf[128];
+	int num_attr = 0;
+	int count;
 
-	if (attr->sta_addr)
+	*multi = 0;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next)
+		sta->radius_das_match = 1;
+
+	if (attr->sta_addr) {
+		num_attr++;
 		sta = ap_get_sta(hapd, attr->sta_addr);
+		if (!sta) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: No Calling-Station-Id match");
+			return NULL;
+		}
 
-	if (sta == NULL && attr->acct_session_id &&
-	    attr->acct_session_id_len == 17) {
+		selected = sta;
 		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (sta != selected)
+				sta->radius_das_match = 0;
+		}
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
+	}
+
+	if (attr->acct_session_id) {
+		num_attr++;
+		if (attr->acct_session_id_len != 17) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: Acct-Session-Id cannot match");
+			return NULL;
+		}
+		count = 0;
+
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (!sta->radius_das_match)
+				continue;
 			os_snprintf(buf, sizeof(buf), "%08X-%08X",
 				    sta->acct_session_id_hi,
 				    sta->acct_session_id_lo);
-			if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
-				break;
+			if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+				sta->radius_das_match = 0;
+			else
+				count++;
 		}
+
+		if (count == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: No matches remaining after Acct-Session-Id check");
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
 	}
 
-	if (sta == NULL && attr->cui) {
+	if (attr->acct_multi_session_id) {
+		num_attr++;
+		if (attr->acct_multi_session_id_len != 17) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: Acct-Multi-Session-Id cannot match");
+			return NULL;
+		}
+		count = 0;
+
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (!sta->radius_das_match)
+				continue;
+			if (!sta->eapol_sm ||
+			    !sta->eapol_sm->acct_multi_session_id_hi) {
+				sta->radius_das_match = 0;
+				continue;
+			}
+			os_snprintf(buf, sizeof(buf), "%08X+%08X",
+				    sta->eapol_sm->acct_multi_session_id_hi,
+				    sta->eapol_sm->acct_multi_session_id_lo);
+			if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+			    0)
+				sta->radius_das_match = 0;
+			else
+				count++;
+		}
+
+		if (count == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS DAS: Acct-Multi-Session-Id match");
+	}
+
+	if (attr->cui) {
+		num_attr++;
+		count = 0;
+
 		for (sta = hapd->sta_list; sta; sta = sta->next) {
 			struct wpabuf *cui;
+
+			if (!sta->radius_das_match)
+				continue;
 			cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
-			if (cui && wpabuf_len(cui) == attr->cui_len &&
+			if (!cui || wpabuf_len(cui) != attr->cui_len ||
 			    os_memcmp(wpabuf_head(cui), attr->cui,
-				      attr->cui_len) == 0)
-				break;
+				      attr->cui_len) != 0)
+				sta->radius_das_match = 0;
+			else
+				count++;
 		}
+
+		if (count == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS DAS: Chargeable-User-Identity match");
 	}
 
-	if (sta == NULL && attr->user_name) {
+	if (attr->user_name) {
+		num_attr++;
+		count = 0;
+
 		for (sta = hapd->sta_list; sta; sta = sta->next) {
 			u8 *identity;
 			size_t identity_len;
+
+			if (!sta->radius_das_match)
+				continue;
 			identity = ieee802_1x_get_identity(sta->eapol_sm,
 							   &identity_len);
-			if (identity &&
-			    identity_len == attr->user_name_len &&
+			if (!identity ||
+			    identity_len != attr->user_name_len ||
 			    os_memcmp(identity, attr->user_name, identity_len)
-			    == 0)
-				break;
+			    != 0)
+				sta->radius_das_match = 0;
+			else
+				count++;
+		}
+
+		if (count == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: No matches remaining after User-Name check");
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS DAS: User-Name match");
+	}
+
+	if (num_attr == 0) {
+		/*
+		 * In theory, we could match all current associations, but it
+		 * seems safer to just reject requests that do not include any
+		 * session identification attributes.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS DAS: No session identification attributes included");
+		return NULL;
+	}
+
+	selected = NULL;
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (sta->radius_das_match) {
+			if (selected) {
+				*multi = 1;
+				return NULL;
+			}
+			selected = sta;
 		}
 	}
 
-	return sta;
+	return selected;
+}
+
+
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+					struct radius_das_attrs *attr)
+{
+	if (!hapd->wpa_auth)
+		return -1;
+	return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
 }
 
 
@@ -667,14 +813,29 @@
 {
 	struct hostapd_data *hapd = ctx;
 	struct sta_info *sta;
+	int multi;
 
 	if (hostapd_das_nas_mismatch(hapd, attr))
 		return RADIUS_DAS_NAS_MISMATCH;
 
-	sta = hostapd_das_find_sta(hapd, attr);
-	if (sta == NULL)
+	sta = hostapd_das_find_sta(hapd, attr, &multi);
+	if (sta == NULL) {
+		if (multi) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: Multiple sessions match - not supported");
+			return RADIUS_DAS_MULTI_SESSION_MATCH;
+		}
+		if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: PMKSA cache entry matched");
+			return RADIUS_DAS_SUCCESS;
+		}
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
 		return RADIUS_DAS_SESSION_NOT_FOUND;
+	}
 
+	wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+		   " - disconnecting", MAC2STR(sta->addr));
 	wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
 
 	hostapd_drv_sta_deauth(hapd, sta->addr,
@@ -701,7 +862,7 @@
 static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
 {
 	struct hostapd_bss_config *conf = hapd->conf;
-	u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+	u8 ssid[SSID_MAX_LEN + 1];
 	int ssid_len, set_ssid;
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
@@ -1217,6 +1378,7 @@
 	size_t j;
 	u8 *prev_addr;
 	int delay_apply_cfg = 0;
+	int res_dfs_offload = 0;
 
 	if (err)
 		goto fail;
@@ -1243,6 +1405,23 @@
 					goto fail;
 				return res;
 			}
+		} else {
+			/* If DFS is offloaded to the driver */
+			res_dfs_offload = hostapd_handle_dfs_offload(iface);
+			if (res_dfs_offload <= 0) {
+				if (res_dfs_offload < 0)
+					goto fail;
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "Proceed with AP/channel setup");
+				/*
+				 * If this is a DFS channel, move to completing
+				 * AP setup.
+				 */
+				if (res_dfs_offload == 1)
+					goto dfs_offload;
+				/* Otherwise fall through. */
+			}
 		}
 #endif /* NEED_AP_MLME */
 
@@ -1337,6 +1516,19 @@
 			goto fail;
 	}
 
+	if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+	    !res_dfs_offload) {
+		/*
+		 * If freq is DFS, and DFS is offloaded to the driver, then wait
+		 * for CAC to complete.
+		 */
+		wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
+		return res_dfs_offload;
+	}
+
+#ifdef NEED_AP_MLME
+dfs_offload:
+#endif /* NEED_AP_MLME */
 	hostapd_set_state(iface, HAPD_IFACE_ENABLED);
 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
 	if (hapd->setup_complete_cb)
@@ -1428,6 +1620,7 @@
 	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
 		   hapd->conf->iface);
 	hostapd_bss_deinit_no_free(hapd);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
 	hostapd_cleanup(hapd);
 }
 
@@ -1440,6 +1633,8 @@
 	if (iface == NULL)
 		return;
 
+	hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+
 #ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
 	hostapd_stop_setup_timers(iface);
@@ -1872,33 +2067,37 @@
 }
 
 
-static struct hostapd_iface * hostapd_data_alloc(
-	struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
+			      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_calloc(conf->num_bss,
 				    sizeof(struct hostapd_data *));
 	if (hapd_iface->bss == NULL)
-		return NULL;
+		return -1;
 
 	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;
+		if (hapd == NULL) {
+			while (i > 0) {
+				i--;
+				os_free(hapd_iface->bss[i]);
+				hapd_iface->bss[i] = NULL;
+			}
+			os_free(hapd_iface->bss);
+			hapd_iface->bss = NULL;
+			return -1;
+		}
 		hapd->msg_ctx = hapd;
 	}
 
-	hapd_iface->interfaces = interfaces;
+	hapd_iface->conf = conf;
+	hapd_iface->num_bss = conf->num_bss;
 
-	return hapd_iface;
+	return 0;
 }
 
 
@@ -1945,13 +2144,10 @@
 		}
 
 		if (new_iface) {
-			if (interfaces->driver_init(hapd_iface)) {
-				interfaces->count--;
+			if (interfaces->driver_init(hapd_iface))
 				goto fail;
-			}
 
 			if (hostapd_setup_interface(hapd_iface)) {
-				interfaces->count--;
 				hostapd_deinit_driver(
 					hapd_iface->bss[0]->driver,
 					hapd_iface->bss[0]->drv_priv,
@@ -1975,6 +2171,8 @@
 				hapd_iface->num_bss--;
 				wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
 					   __func__, hapd, hapd->conf->iface);
+				hostapd_config_free_bss(hapd->conf);
+				hapd->conf = NULL;
 				os_free(hapd);
 				return -1;
 			}
@@ -2005,6 +2203,7 @@
 			   "for interface", __func__);
 		goto fail;
 	}
+	new_iface = hapd_iface;
 
 	if (conf_file && interfaces->config_read_cb) {
 		conf = interfaces->config_read_cb(conf_file);
@@ -2019,17 +2218,18 @@
 		goto fail;
 	}
 
-	hapd_iface = hostapd_data_alloc(interfaces, conf);
-	if (hapd_iface == NULL) {
+	if (hostapd_data_alloc(hapd_iface, conf) < 0) {
 		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
 			   "for hostapd", __func__);
 		goto fail;
 	}
+	conf = NULL;
 
 	if (start_ctrl_iface(hapd_iface) < 0)
 		goto fail;
 
-	wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
+	wpa_printf(MSG_INFO, "Add interface '%s'",
+		   hapd_iface->conf->bss[0]->iface);
 
 	return 0;
 
@@ -2056,6 +2256,10 @@
 			os_free(hapd_iface->bss);
 			hapd_iface->bss = NULL;
 		}
+		if (new_iface) {
+			interfaces->count--;
+			interfaces->iface[interfaces->count] = NULL;
+		}
 		hostapd_cleanup_iface(hapd_iface);
 	}
 	return -1;
@@ -2076,6 +2280,7 @@
 		wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
 			   __func__, hapd, hapd->conf->iface);
 		hostapd_config_free_bss(hapd->conf);
+		hapd->conf = NULL;
 		os_free(hapd);
 
 		iface->num_bss--;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index e291d08..788b118 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -108,6 +108,8 @@
 	struct hostapd_bss_config *conf;
 	int interface_added; /* virtual interface added for this BSS */
 	unsigned int started:1;
+	unsigned int disabled:1;
+	unsigned int reenable_beacon:1;
 
 	u8 own_addr[ETH_ALEN];
 
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 7d672c8..6d84ee4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -15,6 +15,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
@@ -74,7 +75,7 @@
 int hostapd_get_hw_features(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
-	int ret = 0, i, j;
+	int i, j;
 	u16 num_modes, flags;
 	struct hostapd_hw_modes *modes;
 
@@ -137,7 +138,7 @@
 		}
 	}
 
-	return ret;
+	return 0;
 }
 
 
@@ -232,66 +233,16 @@
 #ifdef CONFIG_IEEE80211N
 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 {
-	int sec_chan, ok, j, first;
-	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
-			  184, 192 };
-	size_t k;
+	int pri_chan, sec_chan;
 
 	if (!iface->conf->secondary_channel)
 		return 1; /* HT40 not used */
 
-	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
-	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
-		   "secondary channel: %d",
-		   iface->conf->channel, sec_chan);
+	pri_chan = iface->conf->channel;
+	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
 
-	/* Verify that HT40 secondary channel is an allowed 20 MHz
-	 * channel */
-	ok = 0;
-	for (j = 0; j < iface->current_mode->num_channels; j++) {
-		struct hostapd_channel_data *chan =
-			&iface->current_mode->channels[j];
-		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-		    chan->chan == sec_chan) {
-			ok = 1;
-			break;
-		}
-	}
-	if (!ok) {
-		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
-			   sec_chan);
-		return 0;
-	}
-
-	/*
-	 * Verify that HT40 primary,secondary channel pair is allowed per
-	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
-	 * 2.4 GHz rules allow all cases where the secondary channel fits into
-	 * the list of allowed channels (already checked above).
-	 */
-	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
-		return 1;
-
-	if (iface->conf->secondary_channel > 0)
-		first = iface->conf->channel;
-	else
-		first = sec_chan;
-
-	ok = 0;
-	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
-		if (first == allowed[k]) {
-			ok = 1;
-			break;
-		}
-	}
-	if (!ok) {
-		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
-			   iface->conf->channel,
-			   iface->conf->secondary_channel);
-		return 0;
-	}
-
-	return 1;
+	return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
+					 sec_chan);
 }
 
 
@@ -307,224 +258,34 @@
 }
 
 
-static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
-					int *pri_chan, int *sec_chan)
-{
-	struct ieee80211_ht_operation *oper;
-	struct ieee802_11_elems elems;
-
-	*pri_chan = *sec_chan = 0;
-
-	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
-	if (elems.ht_operation &&
-	    elems.ht_operation_len >= sizeof(*oper)) {
-		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
-		*pri_chan = oper->primary_chan;
-		if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
-			int sec = oper->ht_param &
-				HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
-			if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
-				*sec_chan = *pri_chan + 4;
-			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
-				*sec_chan = *pri_chan - 4;
-		}
-	}
-}
-
-
 static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
 				     struct wpa_scan_results *scan_res)
 {
-	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
-	int bss_pri_chan, bss_sec_chan;
-	size_t i;
-	int match;
+	int pri_chan, sec_chan;
+	int res;
 
 	pri_chan = iface->conf->channel;
 	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
-	if (iface->conf->secondary_channel > 0)
-		sec_freq = pri_freq + 20;
-	else
-		sec_freq = pri_freq - 20;
 
-	/*
-	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
-	 * channel, but not on selected PRI channel.
-	 */
-	pri_bss = sec_bss = 0;
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		if (bss->freq == pri_freq)
-			pri_bss++;
-		else if (bss->freq == sec_freq)
-			sec_bss++;
-	}
-	if (sec_bss && !pri_bss) {
-		if (!experiment("NoSwapWifiPrimaryChannel")) {
-			wpa_printf(MSG_INFO, "Switch own primary and secondary "
-				   "channel to get secondary channel with no Beacons "
-				   "from other BSSes");
-			ieee80211n_switch_pri_sec(iface);
-			return 1;
-		} else {
-			wpa_printf(MSG_INFO, "NoSwapPrimaryWifiChannel: "
-				   "would have swapped channels (1).");
-		}
-	}
+	res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
 
-	/*
-	 * Match PRI/SEC channel with any existing HT40 BSS on the same
-	 * channels that we are about to use (if already mixed order in
-	 * existing BSSes, use own preference).
-	 */
-	match = 0;
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
-		if (pri_chan == bss_pri_chan &&
-		    sec_chan == bss_sec_chan) {
-			match = 1;
-			break;
-		}
-	}
-	if (!match) {
-		for (i = 0; i < scan_res->num; i++) {
-			struct wpa_scan_res *bss = scan_res->res[i];
-			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
-						    &bss_sec_chan);
-			if (pri_chan == bss_sec_chan &&
-			    sec_chan == bss_pri_chan) {
-				if (!experiment("NoSwapWifiPrimaryChannel")) {
-					wpa_printf(MSG_INFO, "Switch own primary and "
-						   "secondary channel due to BSS "
-						   "overlap with " MACSTR,
-						   MAC2STR(bss->bssid));
-					ieee80211n_switch_pri_sec(iface);
-				} else {
-					wpa_printf(MSG_INFO, "NoSwapPrimaryWifiChannel: "
-						   "would have swapped channels (2).");
-				}
-				break;
-			}
-		}
-	}
+	if (res == 2)
+		ieee80211n_switch_pri_sec(iface);
 
-	return 1;
-}
-
-
-static int ieee80211n_check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq,
-				      int start, int end)
-{
-	struct ieee802_11_elems elems;
-	struct ieee80211_ht_operation *oper;
-
-	if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
-		return 0;
-
-	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
-	if (!elems.ht_capabilities) {
-		wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
-			   MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
-		return 1;
-	}
-
-	if (elems.ht_operation &&
-	    elems.ht_operation_len >= sizeof(*oper)) {
-		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
-		if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
-			return 0;
-
-		wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
-			   MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
-		return 1;
-	}
-	return 0;
+	return !!res;
 }
 
 
 static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
 				      struct wpa_scan_results *scan_res)
 {
-	int pri_freq, sec_freq;
-	int affected_start, affected_end;
-	size_t i;
+	int pri_chan, sec_chan;
 
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
-	if (iface->conf->secondary_channel > 0)
-		sec_freq = pri_freq + 20;
-	else
-		sec_freq = pri_freq - 20;
-	affected_start = (pri_freq + sec_freq) / 2 - 25;
-	affected_end = (pri_freq + sec_freq) / 2 + 25;
-	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
-		   affected_start, affected_end);
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		int pri = bss->freq;
-		int sec = pri;
-		int sec_chan, pri_chan;
-		struct ieee802_11_elems elems;
+	pri_chan = iface->conf->channel;
+	sec_chan = pri_chan + iface->conf->secondary_channel * 4;
 
-		/* Check for overlapping 20 MHz BSS */
-		if (ieee80211n_check_20mhz_bss(bss, pri_freq, affected_start,
-					       affected_end)) {
-			wpa_printf(MSG_DEBUG,
-				   "Overlapping 20 MHz BSS is found");
-			return 0;
-		}
-
-		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
-		if (sec_chan) {
-			if (sec_chan < pri_chan)
-				sec = pri - 20;
-			else
-				sec = pri + 20;
-		}
-
-		if ((pri < affected_start || pri > affected_end) &&
-		    (sec < affected_start || sec > affected_end))
-			continue; /* not within affected channel range */
-
-		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
-			   " freq=%d pri=%d sec=%d",
-			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
-		if (sec_chan) {
-			if (pri_freq != pri || sec_freq != sec) {
-				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
-					   "mismatch with BSS " MACSTR
-					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
-					   MAC2STR(bss->bssid),
-					   pri, sec, pri_chan,
-					   sec > pri ? '+' : '-',
-					   pri_freq, sec_freq);
-				return 0;
-			}
-		}
-
-		ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
-				       0);
-		if (elems.ht_capabilities &&
-		    elems.ht_capabilities_len >=
-		    sizeof(struct ieee80211_ht_capabilities)) {
-			struct ieee80211_ht_capabilities *ht_cap =
-				(struct ieee80211_ht_capabilities *)
-				elems.ht_capabilities;
-
-			if (le_to_host16(ht_cap->ht_capabilities_info) &
-			    HT_CAP_INFO_40MHZ_INTOLERANT) {
-				wpa_printf(MSG_DEBUG,
-					   "40 MHz Intolerant is set on channel %d in BSS "
-					   MACSTR, pri, MAC2STR(bss->bssid));
-				return 0;
-			}
-		}
-	}
-
-	return 1;
+	return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
+			       sec_chan);
 }
 
 
@@ -762,7 +523,11 @@
 		return 0;
 	}
 
-	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+	/*
+	 * Driver ACS chosen channel may not be HT40 due to internal driver
+	 * restrictions.
+	 */
+	if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
 	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
 		wpa_printf(MSG_ERROR, "Driver does not support configured "
 			   "HT capability [HT40*]");
@@ -893,12 +658,31 @@
 
 static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
 {
-	u32 hw = iface->current_mode->vht_capab;
+	struct hostapd_hw_modes *mode = iface->current_mode;
+	u32 hw = mode->vht_capab;
 	u32 conf = iface->conf->vht_capab;
 
 	wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
 		   hw, conf);
 
+	if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    iface->conf->bss[0]->vendor_vht &&
+	    mode->vht_capab == 0 && iface->hw_features) {
+		int i;
+
+		for (i = 0; i < iface->num_hw_features; i++) {
+			if (iface->hw_features[i].mode ==
+			    HOSTAPD_MODE_IEEE80211A) {
+				mode = &iface->hw_features[i];
+				hw = mode->vht_capab;
+				wpa_printf(MSG_DEBUG,
+					   "update hw vht capab based on 5 GHz band: 0x%x",
+					   hw);
+				break;
+			}
+		}
+	}
+
 #define VHT_CAP_CHECK(cap) \
 	do { \
 		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
@@ -1166,35 +950,11 @@
 
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
 {
-	int i;
-
-	if (!hapd->iface->current_mode)
-		return 0;
-
-	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
-		struct hostapd_channel_data *ch =
-			&hapd->iface->current_mode->channels[i];
-		if (ch->chan == chan)
-			return ch->freq;
-	}
-
-	return 0;
+	return hw_get_freq(hapd->iface->current_mode, chan);
 }
 
 
 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
 {
-	int i;
-
-	if (!hapd->iface->current_mode)
-		return 0;
-
-	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
-		struct hostapd_channel_data *ch =
-			&hapd->iface->current_mode->channels[i];
-		if (ch->freq == freq)
-			return ch->chan;
-	}
-
-	return 0;
+	return hw_get_chan(hapd->iface->current_mode, freq);
 }
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 0f67ab8..ca7f22b 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -36,6 +36,11 @@
 	return -1;
 }
 
+static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
+{
+	return -1;
+}
+
 static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
 {
 	return -100;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 9140f3e..62b40d2 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -137,8 +137,7 @@
 }
 
 
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int probe)
+u16 hostapd_own_capab_info(struct hostapd_data *hapd)
 {
 	int capab = WLAN_CAPABILITY_ESS;
 	int privacy;
@@ -171,20 +170,6 @@
 		privacy = 1;
 #endif /* CONFIG_HS20 */
 
-	if (sta) {
-		int policy, def_klen;
-		if (probe && sta->ssid_probe) {
-			policy = sta->ssid_probe->security_policy;
-			def_klen = sta->ssid_probe->wep.default_len;
-		} else {
-			policy = sta->ssid->security_policy;
-			def_klen = sta->ssid->wep.default_len;
-		}
-		privacy = policy != SECURITY_PLAINTEXT;
-		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
-			privacy = 0;
-	}
-
 	if (privacy)
 		capab |= WLAN_CAPABILITY_PRIVACY;
 
@@ -333,6 +318,10 @@
 
 #ifdef CONFIG_SAE
 
+#define dot11RSNASAERetransPeriod 40	/* msec */
+#define dot11RSNASAESync 5		/* attempts */
+
+
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
 					     struct sta_info *sta, int update)
 {
@@ -488,6 +477,66 @@
 }
 
 
+static int sae_check_big_sync(struct sta_info *sta)
+{
+	if (sta->sae->sync > dot11RSNASAESync) {
+		sta->sae->state = SAE_NOTHING;
+		sta->sae->sync = 0;
+		return -1;
+	}
+	return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = eloop_data;
+	int ret;
+
+	if (sae_check_big_sync(sta))
+		return;
+	sta->sae->sync++;
+
+	switch (sta->sae->state) {
+	case SAE_COMMITTED:
+		ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+		eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+				       auth_sae_retransmit_timer, hapd, sta);
+		break;
+	case SAE_CONFIRMED:
+		ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+		eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+				       auth_sae_retransmit_timer, hapd, sta);
+		break;
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (ret != WLAN_STATUS_SUCCESS)
+		wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+				     struct sta_info *sta)
+{
+	if (!(hapd->conf->mesh & MESH_ENABLED))
+		return;
+
+	eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+	eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+			       auth_sae_retransmit_timer, hapd, sta);
+}
+
+
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *bssid, u8 auth_transaction)
 {
@@ -535,6 +584,8 @@
 				 * when receiving Confirm from STA.
 				 */
 			}
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
@@ -543,6 +594,7 @@
 		}
 		break;
 	case SAE_COMMITTED:
+		sae_clear_retransmit_timer(hapd, sta);
 		if (auth_transaction == 1) {
 			if (sae_process_commit(sta->sae) < 0)
 				return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -551,14 +603,22 @@
 			if (ret)
 				return ret;
 			sta->sae->state = SAE_CONFIRMED;
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 		} else if (hapd->conf->mesh & MESH_ENABLED) {
 			/*
 			 * In mesh case, follow SAE finite state machine and
-			 * send Commit now.
+			 * send Commit now, if sync count allows.
 			 */
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
 			if (ret)
 				return ret;
+
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			/*
 			 * For instructure BSS, send the postponed Confirm from
@@ -580,7 +640,12 @@
 		}
 		break;
 	case SAE_CONFIRMED:
+		sae_clear_retransmit_timer(hapd, sta);
 		if (auth_transaction == 1) {
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
 			if (ret)
 				return ret;
@@ -591,6 +656,8 @@
 			ret = auth_sae_send_confirm(hapd, sta, bssid);
 			if (ret)
 				return ret;
+
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			sta->flags |= WLAN_STA_AUTH;
 			sta->auth_alg = WLAN_AUTH_SAE;
@@ -608,6 +675,10 @@
 				   MAC2STR(sta->addr));
 			ap_free_sta(hapd, sta);
 		} else {
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_confirm(hapd, sta, bssid);
 			sae_clear_temp_data(sta->sae);
 			if (ret)
@@ -637,6 +708,7 @@
 		if (sta->sae == NULL)
 			return;
 		sta->sae->state = SAE_NOTHING;
+		sta->sae->sync = 0;
 	}
 
 	if (auth_transaction == 1) {
@@ -690,6 +762,8 @@
 				return;
 			}
 			sta->sae->state = SAE_COMMITTED;
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 			return;
 		}
 
@@ -760,6 +834,39 @@
 	}
 	wpabuf_free(data);
 }
+
+
+/**
+ * auth_sae_init_committed - Send COMMIT and start SAE in committed state
+ * @hapd: BSS data for the device initiating the authentication
+ * @sta: the peer to which commit authentication frame is sent
+ *
+ * This function implements Init event handling (IEEE Std 802.11-2012,
+ * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
+ * sta->sae structure should be initialized appropriately via a call to
+ * sae_prepare_commit().
+ */
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int ret;
+
+	if (!sta->sae || !sta->sae->tmp)
+		return -1;
+
+	if (sta->sae->state != SAE_NOTHING)
+		return -1;
+
+	ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+	if (ret)
+		return -1;
+
+	sta->sae->state = SAE_COMMITTED;
+	sta->sae->sync = 0;
+	sae_set_retransmit_timer(hapd, sta);
+
+	return 0;
+}
+
 #endif /* CONFIG_SAE */
 
 
@@ -1186,8 +1293,7 @@
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
 #ifdef CONFIG_IEEE80211N
-	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
-				 elems.ht_capabilities_len);
+	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
 	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
@@ -1200,8 +1306,7 @@
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
-	resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
-				  elems.vht_capabilities_len);
+	resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
 
@@ -1216,6 +1321,13 @@
 			       "mandatory VHT PHY - reject association");
 		return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
 	}
+
+	if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+		resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+					   elems.vendor_vht_len);
+		if (resp != WLAN_STATUS_SUCCESS)
+			return resp;
+	}
 #endif /* CONFIG_IEEE80211AC */
 
 #ifdef CONFIG_P2P
@@ -1476,7 +1588,7 @@
 	send_len = IEEE80211_HDRLEN;
 	send_len += sizeof(reply->u.assoc_resp);
 	reply->u.assoc_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+		host_to_le16(hostapd_own_capab_info(hapd));
 	reply->u.assoc_resp.status_code = host_to_le16(status_code);
 	reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
 	/* Supported rates */
@@ -1505,8 +1617,10 @@
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
-	p = hostapd_eid_vht_capabilities(hapd, p);
-	p = hostapd_eid_vht_operation(hapd, p);
+	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+		p = hostapd_eid_vht_capabilities(hapd, p);
+		p = hostapd_eid_vht_operation(hapd, p);
+	}
 #endif /* CONFIG_IEEE80211AC */
 
 	p = hostapd_eid_ext_capab(hapd, p);
@@ -1514,6 +1628,11 @@
 	if (sta->qos_map_enabled)
 		p = hostapd_eid_qos_map_set(hapd, p);
 
+#ifdef CONFIG_IEEE80211AC
+	if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+		p = hostapd_eid_vendor_vht(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
 	if (sta->flags & WLAN_STA_WMM)
 		p = hostapd_eid_wmm(hapd, p);
 
@@ -2252,7 +2371,7 @@
 				       char *ifname_wds)
 {
 	int i;
-	struct hostapd_ssid *ssid = sta->ssid;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
 
 	if (hapd->conf->ieee802_1x || hapd->conf->wpa)
 		return;
@@ -2397,11 +2516,11 @@
 		 * so bind it to the selected VLAN interface now, since the
 		 * interface selection is not going to change anymore.
 		 */
-		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+		if (ap_sta_bind_vlan(hapd, sta) < 0)
 			return;
 	} else if (sta->vlan_id) {
 		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
-		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+		if (ap_sta_bind_vlan(hapd, sta) < 0)
 			return;
 	}
 
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index cf0d3f2..44c1bff 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,6 +14,7 @@
 struct sta_info;
 struct hostapd_frame_info;
 struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -40,8 +41,7 @@
 	return 0;
 }
 #endif /* NEED_AP_MLME */
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int probe);
+u16 hostapd_own_capab_info(struct hostapd_data *hapd);
 void ap_ht2040_timeout(void *eloop_data, void *user_data);
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
@@ -51,6 +51,7 @@
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
 int hostapd_ht_operation_update(struct hostapd_iface *iface);
 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
 				  const u8 *addr, const u8 *trans_id);
@@ -61,12 +62,15 @@
 			   struct ieee80211_vht_capabilities *vht_cap,
 			   struct ieee80211_vht_capabilities *neg_vht_cap);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
-		      const u8 *ht_capab, size_t ht_capab_len);
+		      const u8 *ht_capab);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+			const u8 *ie, size_t len);
+
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
 void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
 void ht40_intolerant_remove(struct hostapd_iface *iface, 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);
+		       const u8 *vht_capab);
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_opmode);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
@@ -89,4 +93,15 @@
 void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
 
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
+#ifdef CONFIG_SAE
+void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+				struct sta_info *sta);
+#else /* CONFIG_SAE */
+static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+					      struct sta_info *sta)
+{
+}
+#endif /* CONFIG_SAE */
+
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 3f299f3..11fde2a 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -209,7 +209,7 @@
 	struct hostapd_iface *iface = hapd->iface;
 	struct ieee80211_2040_bss_coex_ie *bc_ie;
 	struct ieee80211_2040_intol_chan_report *ic_report;
-	int is_ht_allowed = 1;
+	int is_ht40_allowed = 1;
 	int i;
 	const u8 *start = (const u8 *) mgmt;
 	const u8 *data = start + IEEE80211_HDRLEN + 2;
@@ -242,7 +242,7 @@
 			       HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "20 MHz BSS width request bit is set in BSS coexistence information field");
-		is_ht_allowed = 0;
+		is_ht40_allowed = 0;
 	}
 
 	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
@@ -250,7 +250,7 @@
 			       HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "40 MHz intolerant bit is set in BSS coexistence information field");
-		is_ht_allowed = 0;
+		is_ht40_allowed = 0;
 	}
 
 	if (start + len - data >= 3 &&
@@ -276,13 +276,13 @@
 				       HOSTAPD_LEVEL_DEBUG,
 				       "20_40_INTOLERANT channel %d reported",
 				       chan);
-			is_ht_allowed = 0;
+			is_ht40_allowed = 0;
 		}
 	}
-	wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
-		   is_ht_allowed, iface->num_sta_ht40_intolerant);
+	wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
+		   is_ht40_allowed, iface->num_sta_ht40_intolerant);
 
-	if (!is_ht_allowed &&
+	if (!is_ht40_allowed &&
 	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
 		if (iface->conf->secondary_channel) {
 			hostapd_logger(hapd, mgmt->sa,
@@ -292,7 +292,8 @@
 			iface->conf->secondary_channel = 0;
 			ieee802_11_set_beacons(iface);
 		}
-		if (!iface->num_sta_ht40_intolerant) {
+		if (!iface->num_sta_ht40_intolerant &&
+		    iface->conf->obss_interval) {
 			unsigned int delay_time;
 			delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
 				iface->conf->obss_interval;
@@ -309,12 +310,15 @@
 
 
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
-		      const u8 *ht_capab, size_t ht_capab_len)
+		      const u8 *ht_capab)
 {
-	/* Disable HT caps for STAs associated to no-HT BSSes. */
+	/*
+	 * Disable HT caps for STAs associated to no-HT BSSes, or for stations
+	 * that did not specify a valid WMM IE in the (Re)Association Request
+	 * frame.
+	 */
 	if (!ht_capab ||
-	    ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
-	    hapd->conf->disable_11n) {
+	    !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
 		sta->flags &= ~WLAN_STA_HT;
 		os_free(sta->ht_capabilities);
 		sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 437cf50..5bf1b5d 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -22,12 +22,25 @@
 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
 {
 	struct ieee80211_vht_capabilities *cap;
+	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
 	u8 *pos = eid;
 
-	if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
-	    hapd->conf->disable_11ac)
+	if (!mode)
 		return eid;
 
+	if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+	    mode->vht_capab == 0 && hapd->iface->hw_features) {
+		int i;
+
+		for (i = 0; i < hapd->iface->num_hw_features; i++) {
+			if (hapd->iface->hw_features[i].mode ==
+			    HOSTAPD_MODE_IEEE80211A) {
+				mode = &hapd->iface->hw_features[i];
+				break;
+			}
+		}
+	}
+
 	*pos++ = WLAN_EID_VHT_CAP;
 	*pos++ = sizeof(*cap);
 
@@ -37,8 +50,7 @@
 		hapd->iface->conf->vht_capab);
 
 	/* Supported MCS set comes from hw */
-	os_memcpy(&cap->vht_supported_mcs_set,
-	          hapd->iface->current_mode->vht_mcs_set, 8);
+	os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
 
 	pos += sizeof(*cap);
 
@@ -51,9 +63,6 @@
 	struct ieee80211_vht_operation *oper;
 	u8 *pos = eid;
 
-	if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
-		return eid;
-
 	*pos++ = WLAN_EID_VHT_OPERATION;
 	*pos++ = sizeof(*oper);
 
@@ -81,13 +90,54 @@
 }
 
 
+static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
+			       const u8 *sta_vht_capab)
+{
+	const struct ieee80211_vht_capabilities *vht_cap;
+	struct ieee80211_vht_capabilities ap_vht_cap;
+	u16 sta_rx_mcs_set, ap_tx_mcs_set;
+	int i;
+
+	if (!mode)
+		return 1;
+
+	/*
+	 * Disable VHT caps for STAs for which there is not even a single
+	 * allowed MCS in any supported number of streams, i.e., STA is
+	 * advertising 3 (not supported) as VHT MCS rates for all supported
+	 * stream cases.
+	 */
+	os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
+		  sizeof(ap_vht_cap.vht_supported_mcs_set));
+	vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
+
+	/* AP Tx MCS map vs. STA Rx MCS map */
+	sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
+	ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
+
+	for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
+		if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
+			continue;
+
+		if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
+			continue;
+
+		return 1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "No matching VHT MCS found between AP TX and STA RX");
+	return 0;
+}
+
+
 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
-		       const u8 *vht_capab, size_t vht_capab_len)
+		       const u8 *vht_capab)
 {
 	/* 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) {
+	    hapd->conf->disable_11ac ||
+	    !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
 		sta->flags &= ~WLAN_STA_VHT;
 		os_free(sta->vht_capabilities);
 		sta->vht_capabilities = NULL;
@@ -109,6 +159,66 @@
 }
 
 
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+			const u8 *ie, size_t len)
+{
+	const u8 *vht_capab;
+	unsigned int vht_capab_len;
+
+	if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+	    hapd->conf->disable_11ac)
+		goto no_capab;
+
+	/* The VHT Capabilities element embedded in vendor VHT */
+	vht_capab = ie + 5;
+	if (vht_capab[0] != WLAN_EID_VHT_CAP)
+		goto no_capab;
+	vht_capab_len = vht_capab[1];
+	if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+	    (int) vht_capab_len > ie + len - vht_capab - 2)
+		goto no_capab;
+	vht_capab += 2;
+
+	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 | WLAN_STA_VENDOR_VHT;
+	os_memcpy(sta->vht_capabilities, vht_capab,
+		  sizeof(struct ieee80211_vht_capabilities));
+	return WLAN_STATUS_SUCCESS;
+
+no_capab:
+	sta->flags &= ~WLAN_STA_VENDOR_VHT;
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+
+	if (!hapd->iface->current_mode)
+		return eid;
+
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = (5 +		/* The Vendor OUI, type and subtype */
+		  2 + sizeof(struct ieee80211_vht_capabilities) +
+		  2 + sizeof(struct ieee80211_vht_operation));
+
+	WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
+	pos += 4;
+	*pos++ = VENDOR_VHT_SUBTYPE;
+	pos = hostapd_eid_vht_capabilities(hapd, pos);
+	pos = hostapd_eid_vht_operation(hapd, pos);
+
+	return pos;
+}
+
+
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_oper_notif)
 {
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f5220b9..5a66291 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1108,8 +1108,6 @@
 
 	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
 	if (pmksa) {
-		int old_vlanid;
-
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
@@ -1123,11 +1121,8 @@
 		sta->eapol_sm->authFail = FALSE;
 		if (sta->eapol_sm->eap)
 			eap_sm_notify_cached(sta->eapol_sm->eap);
-		old_vlanid = sta->vlan_id;
 		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
-		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			sta->vlan_id = 0;
-		ap_sta_bind_vlan(hapd, sta, old_vlanid);
+		ap_sta_bind_vlan(hapd, sta);
 	} else {
 		if (reassoc) {
 			/*
@@ -1211,15 +1206,11 @@
 		if (eap_type >= 0)
 			sm->eap_type_authsrv = eap_type;
 		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
-			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
-			    "??",
-			    eap_type);
+			    eap_server_get_name(0, eap_type), eap_type);
 		break;
 	case EAP_CODE_RESPONSE:
 		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
-			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
-			    "??",
-			    eap_type);
+			    eap_server_get_name(0, eap_type), eap_type);
 		break;
 	case EAP_CODE_SUCCESS:
 		os_strlcpy(buf, "EAP Success", sizeof(buf));
@@ -1275,6 +1266,11 @@
 			sm->eap_if->aaaEapKeyDataLen = len;
 			sm->eap_if->aaaEapKeyAvailable = TRUE;
 		}
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "MS-MPPE: 1x_get_keys, could not get keys: %p  send: %p  recv: %p",
+			   keys, keys ? keys->send : NULL,
+			   keys ? keys->recv : NULL);
 	}
 
 	if (keys) {
@@ -1589,7 +1585,7 @@
 	struct hostapd_data *hapd = data;
 	struct sta_info *sta;
 	u32 session_timeout = 0, termination_action, acct_interim_interval;
-	int session_timeout_set, old_vlanid = 0;
+	int session_timeout_set, vlan_id = 0;
 	struct eapol_state_machine *sm;
 	int override_eapReq = 0;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -1656,20 +1652,27 @@
 
 	switch (hdr->code) {
 	case RADIUS_CODE_ACCESS_ACCEPT:
-		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			sta->vlan_id = 0;
+		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			vlan_id = 0;
 #ifndef CONFIG_NO_VLAN
-		else {
-			old_vlanid = sta->vlan_id;
-			sta->vlan_id = radius_msg_get_vlanid(msg);
-		}
-		if (sta->vlan_id > 0 &&
-		    hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
+		else
+			vlan_id = radius_msg_get_vlanid(msg);
+		if (vlan_id > 0 &&
+		    hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
-				       "VLAN ID %d", sta->vlan_id);
-		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+				       "VLAN ID %d", vlan_id);
+		} else if (vlan_id > 0) {
+			sta->eapol_sm->authFail = TRUE;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "Invalid VLAN ID %d received from RADIUS server",
+				       vlan_id);
+			break;
+		} else if (hapd->conf->ssid.dynamic_vlan ==
+			   DYNAMIC_VLAN_REQUIRED) {
 			sta->eapol_sm->authFail = TRUE;
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE8021X,
@@ -1680,7 +1683,9 @@
 		}
 #endif /* CONFIG_NO_VLAN */
 
-		if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
+		sta->vlan_id = vlan_id;
+		if ((sta->flags & WLAN_STA_ASSOC) &&
+		    ap_sta_bind_vlan(hapd, sta) < 0)
 			break;
 
 		sta->session_timeout_set = !!session_timeout_set;
@@ -1925,10 +1930,11 @@
 	struct hostapd_data *hapd = ctx;
 	const struct hostapd_eap_user *eap_user;
 	int i;
+	int rv = -1;
 
 	eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
 	if (eap_user == NULL)
-		return -1;
+		goto out;
 
 	os_memset(user, 0, sizeof(*user));
 	user->phase2 = phase2;
@@ -1940,7 +1946,7 @@
 	if (eap_user->password) {
 		user->password = os_malloc(eap_user->password_len);
 		if (user->password == NULL)
-			return -1;
+			goto out;
 		os_memcpy(user->password, eap_user->password,
 			  eap_user->password_len);
 		user->password_len = eap_user->password_len;
@@ -1950,8 +1956,13 @@
 	user->macacl = eap_user->macacl;
 	user->ttls_auth = eap_user->ttls_auth;
 	user->remediation = eap_user->remediation;
+	rv = 0;
 
-	return 0;
+out:
+	if (rv)
+		wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+	return rv;
 }
 
 
@@ -2487,15 +2498,23 @@
 		return len;
 	len += ret;
 
+	if (sm->acct_multi_session_id_hi) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "authMultiSessionId=%08X+%08X\n",
+				  sm->acct_multi_session_id_hi,
+				  sm->acct_multi_session_id_lo);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
+
 	name1 = eap_server_get_name(0, sm->eap_type_authsrv);
 	name2 = eap_server_get_name(0, sm->eap_type_supp);
 	ret = os_snprintf(buf + len, buflen - len,
 			  "last_eap_type_as=%d (%s)\n"
 			  "last_eap_type_sta=%d (%s)\n",
-			  sm->eap_type_authsrv,
-			  name1 ? name1 : "",
-			  sm->eap_type_supp,
-			  name2 ? name2 : "");
+			  sm->eap_type_authsrv, name1,
+			  sm->eap_type_supp, name2);
 	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 4270382..877affe 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
 #include "sta_info.h"
 #include "ap_config.h"
 #include "pmksa_cache_auth.h"
@@ -268,7 +269,9 @@
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
-	if (wpa_key_mgmt_suite_b(akmp))
+	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+	else if (wpa_key_mgmt_suite_b(akmp))
 		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
 	else
 		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
@@ -452,3 +455,74 @@
 
 	return pmksa;
 }
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+			  struct radius_das_attrs *attr)
+{
+	int match = 0;
+
+	if (attr->sta_addr) {
+		if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->acct_multi_session_id) {
+		char buf[20];
+
+		if (attr->acct_multi_session_id_len != 17)
+			return 0;
+		os_snprintf(buf, sizeof(buf), "%08X+%08X",
+			    entry->acct_multi_session_id_hi,
+			    entry->acct_multi_session_id_lo);
+		if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->cui) {
+		if (!entry->cui ||
+		    attr->cui_len != wpabuf_len(entry->cui) ||
+		    os_memcmp(attr->cui, wpabuf_head(entry->cui),
+			      attr->cui_len) != 0)
+			return 0;
+		match++;
+	}
+
+	if (attr->user_name) {
+		if (!entry->identity ||
+		    attr->user_name_len != entry->identity_len ||
+		    os_memcmp(attr->user_name, entry->identity,
+			      attr->user_name_len) != 0)
+			return 0;
+		match++;
+	}
+
+	return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+					   struct radius_das_attrs *attr)
+{
+	int found = 0;
+	struct rsn_pmksa_cache_entry *entry, *prev;
+
+	if (attr->acct_session_id)
+		return -1;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (das_attr_match(entry, attr)) {
+			found++;
+			prev = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, prev);
+			continue;
+		}
+		entry = entry->next;
+	}
+
+	return found ? 0 : -1;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 519555f..8b7be12 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -61,5 +61,7 @@
 			       struct eapol_state_machine *eapol);
 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 			    struct rsn_pmksa_cache_entry *entry);
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+					   struct radius_das_attrs *attr);
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 9f16b88..17ecad5 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -171,6 +171,19 @@
 	    !(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_drv_sta_remove(hapd, sta->addr);
 
+#ifndef CONFIG_NO_VLAN
+	if (sta->vlan_id_bound) {
+		/*
+		 * Need to remove the STA entry before potentially removing the
+		 * VLAN.
+		 */
+		if (hapd->iface->driver_ap_teardown &&
+		    !(sta->flags & WLAN_STA_PREAUTH))
+			hostapd_drv_sta_remove(hapd, sta->addr);
+		vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+	}
+#endif /* CONFIG_NO_VLAN */
+
 	ap_sta_hash_del(hapd, sta);
 	ap_sta_list_del(hapd, sta);
 
@@ -250,6 +263,7 @@
 	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
 	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
 	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	sae_clear_retransmit_timer(hapd, sta);
 
 	ieee802_1x_free_station(sta);
 	wpa_auth_sta_deinit(sta->wpa_sm);
@@ -414,8 +428,15 @@
 			 * but do not disconnect the station now.
 			 */
 			next_time = hapd->conf->ap_max_inactivity + fuzz;
-		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
-			   sta->flags & WLAN_STA_ASSOC) {
+		} else if (inactive_sec == -ENOENT) {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has lost its driver entry",
+				MAC2STR(sta->addr));
+
+			/* Avoid sending client probe on removed client */
+			sta->timeout_next = STA_DISASSOC;
+			goto skip_poll;
+		} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
 			/* station activity detected; reset timeout state */
 			wpa_msg(hapd->msg_ctx, MSG_INFO,
 				"Station " MACSTR " has been active %is ago",
@@ -451,6 +472,7 @@
 	hostapd_write_sta_taxonomy(sta);
 #endif /* CONFIG_CLIENT_TAXONOMY */
 
+skip_poll:
 	if (next_time) {
 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
 			   "for " MACSTR " (%lu seconds)",
@@ -659,7 +681,6 @@
 	hapd->sta_list = sta;
 	hapd->num_sta++;
 	ap_sta_hash_add(hapd, sta);
-	sta->ssid = &hapd->conf->ssid;
 	ap_sta_remove_in_other_bss(hapd, sta);
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	dl_list_init(&sta->ip6addr);
@@ -808,33 +829,19 @@
 #endif /* CONFIG_WPS */
 
 
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-		     int old_vlanid)
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
 {
 #ifndef CONFIG_NO_VLAN
 	const char *iface;
 	struct hostapd_vlan *vlan = NULL;
 	int ret;
-
-	/*
-	 * Do not proceed furthur if the vlan id remains same. We do not want
-	 * duplicate dynamic vlan entries.
-	 */
-	if (sta->vlan_id == old_vlanid)
-		return 0;
-
-	/*
-	 * During 1x reauth, if the vlan id changes, then remove the old id and
-	 * proceed furthur to add the new one.
-	 */
-	if (old_vlanid > 0)
-		vlan_remove_dynamic(hapd, old_vlanid);
+	int old_vlanid = sta->vlan_id_bound;
 
 	iface = hapd->conf->iface;
-	if (sta->ssid->vlan[0])
-		iface = sta->ssid->vlan;
+	if (hapd->conf->ssid.vlan[0])
+		iface = hapd->conf->ssid.vlan;
 
-	if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
 		sta->vlan_id = 0;
 	else if (sta->vlan_id > 0) {
 		struct hostapd_vlan *wildcard_vlan = NULL;
@@ -852,12 +859,21 @@
 			iface = vlan->ifname;
 	}
 
+	/*
+	 * Do not increment ref counters if the VLAN ID remains same, but do
+	 * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
+	 * have been called before.
+	 */
+	if (sta->vlan_id == old_vlanid)
+		goto skip_counting;
+
 	if (sta->vlan_id > 0 && vlan == NULL) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
 			       "binding station to (vlan_id=%d)",
 			       sta->vlan_id);
-		return -1;
+		ret = -1;
+		goto done;
 	} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
 		vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
 		if (vlan == NULL) {
@@ -866,11 +882,12 @@
 				       HOSTAPD_LEVEL_DEBUG, "could not add "
 				       "dynamic VLAN interface for vlan_id=%d",
 				       sta->vlan_id);
-			return -1;
+			ret = -1;
+			goto done;
 		}
 
 		iface = vlan->ifname;
-		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+		if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_DEBUG, "could not "
@@ -883,7 +900,7 @@
 			       HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
 			       "interface '%s'", iface);
 	} else if (vlan && vlan->vlan_id == sta->vlan_id) {
-		if (sta->vlan_id > 0) {
+		if (vlan->dynamic_vlan > 0) {
 			vlan->dynamic_vlan++;
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
@@ -897,7 +914,7 @@
 		 * configuration for the case where hostapd did not yet know
 		 * which keys are to be used when the interface was added.
 		 */
-		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+		if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_DEBUG, "could not "
@@ -907,6 +924,10 @@
 		}
 	}
 
+	/* ref counters have been increased, so mark the station */
+	sta->vlan_id_bound = sta->vlan_id;
+
+skip_counting:
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
 		       "'%s'", iface);
@@ -920,6 +941,12 @@
 			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
 			       "entry to vlan_id=%d", sta->vlan_id);
 	}
+
+	/* During 1x reauth, if the vlan id changes, then remove the old id. */
+	if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
+		vlan_remove_dynamic(hapd, old_vlanid);
+done:
+
 	return ret;
 #else /* CONFIG_NO_VLAN */
 	return 0;
@@ -1149,7 +1176,7 @@
 	int res;
 
 	buf[0] = '\0';
-	res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+	res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 			  (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
 			  (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
 			  (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1167,6 +1194,7 @@
 			  (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
 			  (flags & WLAN_STA_GAS ? "[GAS]" : ""),
 			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
+			  (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
 			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
 			   "[WNM_SLEEP_MODE]" : ""));
 	if (os_snprintf_error(buflen, res))
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 65e71f8..ce8d9fb 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -35,6 +35,7 @@
 #define WLAN_STA_VHT BIT(18)
 #define WLAN_STA_WNM_SLEEP_MODE BIT(19)
 #define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -84,6 +85,7 @@
 	unsigned int remediation:1;
 	unsigned int hs20_deauth_requested:1;
 	unsigned int session_timeout_set:1;
+	unsigned int radius_das_match:1;
 
 	u16 auth_alg;
 
@@ -115,10 +117,8 @@
 	struct wpa_state_machine *wpa_sm;
 	struct rsn_preauth_interface *preauth_iface;
 
-	struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
-	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
-
-	int vlan_id;
+	int vlan_id; /* 0: none, >0: VID */
+	int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
 	 /* PSKs from RADIUS authentication server */
 	struct hostapd_sta_wpa_psk_short *psk;
 
@@ -225,8 +225,7 @@
 int ap_sta_wps_cancel(struct hostapd_data *hapd,
 		      struct sta_info *sta, void *ctx);
 #endif /* CONFIG_WPS */
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-		     int old_vlanid);
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 931968c..d60555a 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -59,6 +59,8 @@
 		if (!osta)
 			continue;
 
+		wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
+			   ohapd->conf->iface, MAC2STR(osta->addr));
 		ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
 	}
 
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 4e4a352..baabbe3 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -485,7 +485,8 @@
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
 	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
+		if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
+			vlan->configured = 1;
 
 			if (hapd->conf->vlan_bridge[0]) {
 				os_snprintf(br_name, sizeof(br_name), "%s%d",
@@ -617,6 +618,7 @@
 	struct ifinfomsg *ifi;
 	int attrlen, nlmsg_len, rta_len;
 	struct rtattr *attr;
+	char ifname[IFNAMSIZ + 1];
 
 	if (len < sizeof(*ifi))
 		return;
@@ -631,29 +633,44 @@
 
 	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
 
+	os_memset(ifname, 0, sizeof(ifname));
 	rta_len = RTA_ALIGN(sizeof(struct rtattr));
 	while (RTA_OK(attr, attrlen)) {
-		char ifname[IFNAMSIZ + 1];
-
 		if (attr->rta_type == IFLA_IFNAME) {
 			int n = attr->rta_len - rta_len;
 			if (n < 0)
 				break;
 
-			os_memset(ifname, 0, sizeof(ifname));
-
-			if ((size_t) n > sizeof(ifname))
-				n = sizeof(ifname);
+			if ((size_t) n >= sizeof(ifname))
+				n = sizeof(ifname) - 1;
 			os_memcpy(ifname, ((char *) attr) + rta_len, n);
 
-			if (del)
-				vlan_dellink(ifname, hapd);
-			else
-				vlan_newlink(ifname, hapd);
 		}
 
 		attr = RTA_NEXT(attr, attrlen);
 	}
+
+	if (!ifname[0])
+		return;
+	if (del && if_nametoindex(ifname)) {
+		 /* interface still exists, race condition ->
+		  * iface has just been recreated */
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+		   del ? "DEL" : "NEW",
+		   ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+	if (del)
+		vlan_dellink(ifname, hapd);
+	else
+		vlan_newlink(ifname, hapd);
 }
 
 
@@ -677,7 +694,7 @@
 	}
 
 	h = (struct nlmsghdr *) buf;
-	while (left >= (int) sizeof(*h)) {
+	while (NLMSG_OK(h, left)) {
 		int len, plen;
 
 		len = h->nlmsg_len;
@@ -698,9 +715,7 @@
 			break;
 		}
 
-		len = NLMSG_ALIGN(len);
-		left -= len;
-		h = (struct nlmsghdr *) ((char *) h + len);
+		h = NLMSG_NEXT(h, left);
 	}
 
 	if (left > 0) {
@@ -769,8 +784,7 @@
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
 
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-			      struct hostapd_ssid *mssid, const char *dyn_vlan)
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
 {
         int i;
 
@@ -780,10 +794,11 @@
 	/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
 	 * functions for setting up dynamic broadcast keys. */
 	for (i = 0; i < 4; i++) {
-		if (mssid->wep.key[i] &&
+		if (hapd->conf->ssid.wep.key[i] &&
 		    hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
-					i == mssid->wep.idx, NULL, 0,
-					mssid->wep.key[i], mssid->wep.len[i]))
+					i == hapd->conf->ssid.wep.idx, NULL, 0,
+					hapd->conf->ssid.wep.key[i],
+					hapd->conf->ssid.wep.len[i]))
 		{
 			wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
 				   "encryption for dynamic VLAN");
@@ -891,7 +906,7 @@
 				       struct hostapd_vlan *vlan,
 				       int vlan_id)
 {
-	struct hostapd_vlan *n;
+	struct hostapd_vlan *n = NULL;
 	char *ifname, *pos;
 
 	if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
@@ -904,28 +919,24 @@
 	if (ifname == NULL)
 		return NULL;
 	pos = os_strchr(ifname, '#');
-	if (pos == NULL) {
-		os_free(ifname);
-		return NULL;
-	}
+	if (pos == NULL)
+		goto free_ifname;
 	*pos++ = '\0';
 
 	n = os_zalloc(sizeof(*n));
-	if (n == NULL) {
-		os_free(ifname);
-		return NULL;
-	}
+	if (n == NULL)
+		goto free_ifname;
 
 	n->vlan_id = vlan_id;
 	n->dynamic_vlan = 1;
 
 	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
 		    pos);
-	os_free(ifname);
 
 	if (hostapd_vlan_if_add(hapd, n->ifname)) {
 		os_free(n);
-		return NULL;
+		n = NULL;
+		goto free_ifname;
 	}
 
 	n->next = hapd->conf->vlan;
@@ -935,6 +946,8 @@
 	ifconfig_up(n->ifname);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
+free_ifname:
+	os_free(ifname);
 	return n;
 }
 
@@ -946,7 +959,8 @@
 	if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
 		return 1;
 
-	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
+	wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
+		   __func__, hapd->conf->iface, vlan_id);
 
 	vlan = hapd->conf->vlan;
 	while (vlan) {
diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h
index 781eaac..fc39443 100644
--- a/src/ap/vlan_init.h
+++ b/src/ap/vlan_init.h
@@ -18,7 +18,6 @@
 				       int vlan_id);
 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
 int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-			      struct hostapd_ssid *mssid,
 			      const char *dyn_vlan);
 #else /* CONFIG_NO_VLAN */
 static inline int vlan_init(struct hostapd_data *hapd)
@@ -43,7 +42,6 @@
 }
 
 static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-					    struct hostapd_ssid *mssid,
 					    const char *dyn_vlan)
 {
 	return -1;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 7e8fb5c..4c8bc10 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -564,8 +564,11 @@
 	if (url) {
 		/* Session Information URL */
 		url_len = os_strlen(url);
-		if (url_len > 255)
+		if (url_len > 255) {
+			os_free(buf);
 			return -1;
+		}
+
 		*pos++ = url_len;
 		os_memcpy(pos, url, url_len);
 		pos += url_len;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7a7fd54..af24cf0 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -67,6 +67,14 @@
 }
 
 
+static inline void wpa_auth_psk_failure_report(
+	struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	if (wpa_auth->cb.psk_failure_report)
+		wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
 static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
 				      const u8 *addr, wpa_eapol_variable var,
 				      int value)
@@ -415,6 +423,7 @@
 						wpa_auth);
 	if (wpa_auth->pmksa == NULL) {
 		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+		os_free(wpa_auth->group);
 		os_free(wpa_auth->wpa_ie);
 		os_free(wpa_auth);
 		return NULL;
@@ -424,6 +433,7 @@
 	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
 	if (wpa_auth->ft_pmk_cache == NULL) {
 		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+		os_free(wpa_auth->group);
 		os_free(wpa_auth->wpa_ie);
 		pmksa_cache_auth_deinit(wpa_auth->pmksa);
 		os_free(wpa_auth);
@@ -847,34 +857,45 @@
 {
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
+	struct wpa_eapol_key_192 *key192;
 	u16 key_info, key_data_length;
 	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
 	       SMK_M1, SMK_M3, SMK_ERROR } msg;
 	char *msgtxt;
 	struct wpa_eapol_ie_parse kde;
 	int ft;
-	const u8 *eapol_key_ie;
-	size_t eapol_key_ie_len;
+	const u8 *eapol_key_ie, *key_data;
+	size_t eapol_key_ie_len, keyhdrlen, mic_len;
 
 	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
 		return;
 
-	if (data_len < sizeof(*hdr) + sizeof(*key))
+	mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+	keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+	if (data_len < sizeof(*hdr) + keyhdrlen)
 		return;
 
 	hdr = (struct ieee802_1x_hdr *) data;
 	key = (struct wpa_eapol_key *) (hdr + 1);
+	key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
 	key_info = WPA_GET_BE16(key->key_info);
-	key_data_length = WPA_GET_BE16(key->key_data_length);
+	if (mic_len == 24) {
+		key_data = (const u8 *) (key192 + 1);
+		key_data_length = WPA_GET_BE16(key192->key_data_length);
+	} else {
+		key_data = (const u8 *) (key + 1);
+		key_data_length = WPA_GET_BE16(key->key_data_length);
+	}
 	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
 		   " key_info=0x%x type=%u key_data_length=%u",
 		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
-	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+	if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
 		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
 			   "key_data overflow (%d > %lu)",
 			   key_data_length,
 			   (unsigned long) (data_len - sizeof(*hdr) -
-					    sizeof(*key)));
+					    keyhdrlen));
 		return;
 	}
 
@@ -1081,8 +1102,7 @@
 			wpa_sta_disconnect(wpa_auth, sm->addr);
 			return;
 		}
-		if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
-				      &kde) < 0) {
+		if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
 					 "received EAPOL-Key msg 2/4 with "
 					 "invalid Key Data contents");
@@ -1241,8 +1261,7 @@
 		 */
 		if (msg == SMK_ERROR) {
 #ifdef CONFIG_PEERKEY
-			wpa_smk_error(wpa_auth, sm, (const u8 *) (key + 1),
-				      key_data_length);
+			wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
 #endif /* CONFIG_PEERKEY */
 			return;
 		} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1257,12 +1276,12 @@
 			wpa_request_new_ptk(sm);
 #ifdef CONFIG_PEERKEY
 		} else if (msg == SMK_M1) {
-			wpa_smk_m1(wpa_auth, sm, key, (const u8 *) (key + 1),
+			wpa_smk_m1(wpa_auth, sm, key, key_data,
 				   key_data_length);
 #endif /* CONFIG_PEERKEY */
 		} else if (key_data_length > 0 &&
-			   wpa_parse_kde_ies((const u8 *) (key + 1),
-					     key_data_length, &kde) == 0 &&
+			   wpa_parse_kde_ies(key_data, key_data_length,
+					     &kde) == 0 &&
 			   kde.mac_addr) {
 		} else {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1300,8 +1319,7 @@
 
 #ifdef CONFIG_PEERKEY
 	if (msg == SMK_M3) {
-		wpa_smk_m3(wpa_auth, sm, key, (const u8 *) (key + 1),
-			   key_data_length);
+		wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
 		return;
 	}
 #endif /* CONFIG_PEERKEY */
@@ -1376,14 +1394,19 @@
 {
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
-	size_t len;
+	struct wpa_eapol_key_192 *key192;
+	size_t len, mic_len, keyhdrlen;
 	int alg;
 	int key_data_len, pad_len = 0;
 	u8 *buf, *pos;
 	int version, pairwise;
 	int i;
+	u8 *key_data;
 
-	len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+	mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+	keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+	len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
 
 	if (force_version)
 		version = force_version;
@@ -1430,6 +1453,8 @@
 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
 	hdr->length = host_to_be16(len  - sizeof(*hdr));
 	key = (struct wpa_eapol_key *) (hdr + 1);
+	key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+	key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
 
 	key->type = sm->wpa == WPA_VERSION_WPA2 ?
 		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1466,8 +1491,11 @@
 		os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
 
 	if (kde && !encr) {
-		os_memcpy(key + 1, kde, kde_len);
-		WPA_PUT_BE16(key->key_data_length, kde_len);
+		os_memcpy(key_data, kde, kde_len);
+		if (mic_len == 24)
+			WPA_PUT_BE16(key192->key_data_length, kde_len);
+		else
+			WPA_PUT_BE16(key->key_data_length, kde_len);
 	} else if (encr && kde) {
 		buf = os_zalloc(key_data_len);
 		if (buf == NULL) {
@@ -1487,29 +1515,44 @@
 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
 		    wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
 		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-			if (aes_wrap(sm->PTK.kek, 16,
-				     (key_data_len - 8) / 8, buf,
-				     (u8 *) (key + 1))) {
+			if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
+				     (key_data_len - 8) / 8, buf, key_data)) {
 				os_free(hdr);
 				os_free(buf);
 				return;
 			}
-			WPA_PUT_BE16(key->key_data_length, key_data_len);
-		} else {
+			if (mic_len == 24)
+				WPA_PUT_BE16(key192->key_data_length,
+					     key_data_len);
+			else
+				WPA_PUT_BE16(key->key_data_length,
+					     key_data_len);
+		} else if (sm->PTK.kek_len == 16) {
 			u8 ek[32];
 			os_memcpy(key->key_iv,
 				  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
 			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
 			os_memcpy(ek, key->key_iv, 16);
-			os_memcpy(ek + 16, sm->PTK.kek, 16);
-			os_memcpy(key + 1, buf, key_data_len);
-			rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
-			WPA_PUT_BE16(key->key_data_length, key_data_len);
+			os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
+			os_memcpy(key_data, buf, key_data_len);
+			rc4_skip(ek, 32, 256, key_data, key_data_len);
+			if (mic_len == 24)
+				WPA_PUT_BE16(key192->key_data_length,
+					     key_data_len);
+			else
+				WPA_PUT_BE16(key->key_data_length,
+					     key_data_len);
+		} else {
+			os_free(hdr);
+			os_free(buf);
+			return;
 		}
 		os_free(buf);
 	}
 
 	if (key_info & WPA_KEY_INFO_MIC) {
+		u8 *key_mic;
+
 		if (!sm->PTK_valid) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
 					"PTK not valid when sending EAPOL-Key "
@@ -1517,8 +1560,11 @@
 			os_free(hdr);
 			return;
 		}
-		wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
-				  (u8 *) hdr, len, key->key_mic);
+
+		key_mic = key192->key_mic; /* same offset for key and key192 */
+		wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+				  sm->wpa_key_mgmt, version,
+				  (u8 *) hdr, len, key_mic);
 #ifdef CONFIG_TESTING_OPTIONS
 		if (!pairwise &&
 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1526,7 +1572,7 @@
 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"Corrupting group EAPOL-Key Key MIC");
-			key->key_mic[0]++;
+			key_mic[0]++;
 		}
 #endif /* CONFIG_TESTING_OPTIONS */
 	}
@@ -1575,23 +1621,27 @@
 {
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
+	struct wpa_eapol_key_192 *key192;
 	u16 key_info;
 	int ret = 0;
-	u8 mic[16];
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+	size_t mic_len = wpa_mic_len(akmp);
 
 	if (data_len < sizeof(*hdr) + sizeof(*key))
 		return -1;
 
 	hdr = (struct ieee802_1x_hdr *) data;
 	key = (struct wpa_eapol_key *) (hdr + 1);
+	key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
 	key_info = WPA_GET_BE16(key->key_info);
-	os_memcpy(mic, key->key_mic, 16);
-	os_memset(key->key_mic, 0, 16);
-	if (wpa_eapol_key_mic(PTK->kck, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
-			      data, data_len, key->key_mic) ||
-	    os_memcmp_const(mic, key->key_mic, 16) != 0)
+	os_memcpy(mic, key192->key_mic, mic_len);
+	os_memset(key192->key_mic, 0, mic_len);
+	if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
+			      key_info & WPA_KEY_INFO_TYPE_MASK,
+			      data, data_len, key192->key_mic) ||
+	    os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
 		ret = -1;
-	os_memcpy(key->key_mic, mic, 16);
+	os_memcpy(key192->key_mic, mic, mic_len);
 	return ret;
 }
 
@@ -1840,8 +1890,12 @@
 		}
 #endif /* CONFIG_IEEE80211R */
 	} else {
-		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+			   sm->wpa_auth->cb.get_msk);
+		sm->Disconnect = TRUE;
+		return;
 	}
+	os_memset(msk, 0, sizeof(msk));
 
 	sm->req_replay_counter_used = 0;
 	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -1928,25 +1982,21 @@
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 			  const u8 *pmk, struct wpa_ptk *ptk)
 {
-	size_t ptk_len = wpa_cipher_key_len(sm->pairwise) + 32;
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-		return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+		return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #endif /* CONFIG_IEEE80211R */
 
-	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
-		       sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
-		       (u8 *) ptk, ptk_len,
-		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
-	return 0;
+	return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
+			      ptk, sm->wpa_key_mgmt, sm->pairwise);
 }
 
 
 SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 {
 	struct wpa_ptk PTK;
-	int ok = 0;
+	int ok = 0, psk_found = 0;
 	const u8 *pmk = NULL;
 
 	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
@@ -1962,6 +2012,7 @@
 					       sm->p2p_dev_addr, pmk);
 			if (pmk == NULL)
 				break;
+			psk_found = 1;
 		} else
 			pmk = sm->PMK;
 
@@ -1981,6 +2032,8 @@
 	if (!ok) {
 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 				"invalid MIC in msg 2/4 of 4-Way Handshake");
+		if (psk_found)
+			wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
 		return;
 	}
 
@@ -2271,7 +2324,7 @@
 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
 		int klen = wpa_cipher_key_len(sm->pairwise);
 		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk1, klen)) {
+				     sm->PTK.tk, klen)) {
 			wpa_printf(MSG_ERROR, "wpa_auth_set_key error");
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
 			return;
@@ -3172,7 +3225,7 @@
 		return -1;
 
 	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
-				 sm->PTK.kck, sizeof(sm->PTK.kck),
+				 sm->PTK.kck, sm->PTK.kck_len,
 				 sm->wpa_auth->addr, sm->addr, session_timeout,
 				 eapol, sm->wpa_key_mgmt))
 		return 0;
@@ -3342,3 +3395,21 @@
 	return 0;
 }
 #endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+					 struct radius_das_attrs *attr)
+{
+	return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}
+
+
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group;
+
+	if (!wpa_auth)
+		return;
+	for (group = wpa_auth->group; group; group = group->next)
+		wpa_group_config_group_keys(wpa_auth, group);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 757e49e..e747806 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -12,6 +12,7 @@
 #include "common/defs.h"
 #include "common/eapol_common.h"
 #include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
 
 #ifdef _MSC_VER
 #pragma pack(push, 1)
@@ -146,8 +147,7 @@
 	int group_mgmt_cipher;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
-#define SSID_LEN 32
-	u8 ssid[SSID_LEN];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
 	u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
@@ -189,6 +189,7 @@
 		       const char *txt);
 	void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
 	int (*mic_failure_report)(void *ctx, const u8 *addr);
+	void (*psk_failure_report)(void *ctx, const u8 *addr);
 	void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
 			  int value);
 	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@@ -315,4 +316,9 @@
 
 int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
 
+struct radius_das_attrs;
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+					 struct radius_das_attrs *attr);
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
+
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e061b5e..eeaffbf 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -362,7 +362,7 @@
 
 
 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
-			   struct wpa_ptk *ptk, size_t ptk_len)
+			   struct wpa_ptk *ptk)
 {
 	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
 	u8 pmk_r1[PMK_LEN];
@@ -374,7 +374,6 @@
 	const u8 *ssid = sm->wpa_auth->conf.ssid;
 	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
 
-
 	if (sm->xxkey_len == 0) {
 		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
 			   "derivation");
@@ -396,13 +395,9 @@
 	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
 			    sm->pairwise);
 
-	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
-			  sm->wpa_auth->addr, sm->pmk_r1_name,
-			  (u8 *) ptk, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	return 0;
+	return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+				 sm->wpa_auth->addr, sm->pmk_r1_name,
+				 ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
 }
 
 
@@ -461,7 +456,8 @@
 	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
 	subelem[4] = gsm->GTK_len;
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
-	if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) {
+	if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
+		     subelem + 13)) {
 		os_free(subelem);
 		return NULL;
 	}
@@ -493,7 +489,7 @@
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
 	pos += 6;
 	*pos++ = WPA_IGTK_LEN;
-	if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
+	if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
 		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
 		os_free(subelem);
 		return NULL;
@@ -538,10 +534,8 @@
 		return pos;
 	}
 
-#ifdef NEED_AP_MLME
-	if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+	if (parse.wmm_tspec) {
 		struct wmm_tspec_element *tspec;
-		int res;
 
 		if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
 			wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
@@ -559,7 +553,13 @@
 		}
 		tspec = (struct wmm_tspec_element *) pos;
 		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
-		res = wmm_process_tspec(tspec);
+	}
+
+#ifdef NEED_AP_MLME
+	if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+		int res;
+
+		res = wmm_process_tspec((struct wmm_tspec_element *) pos);
 		wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
 		if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
 			rdie->status_code =
@@ -570,20 +570,17 @@
 		else {
 			/* TSPEC accepted; include updated TSPEC in response */
 			rdie->descr_count = 1;
-			pos += sizeof(*tspec);
+			pos += sizeof(struct wmm_tspec_element);
 		}
 		return pos;
 	}
 #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));
+				       sizeof(struct wmm_tspec_element));
 		if (res >= 0) {
 			if (res)
 				rdie->status_code = host_to_le16(res);
@@ -591,7 +588,7 @@
 				/* TSPEC accepted; include updated TSPEC in
 				 * response */
 				rdie->descr_count = 1;
-				pos += sizeof(*tspec);
+				pos += sizeof(struct wmm_tspec_element);
 			}
 			return pos;
 		}
@@ -745,7 +742,8 @@
 		ric_start = NULL;
 
 	if (auth_alg == WLAN_AUTH_FT &&
-	    wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+	    wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+		       sm->wpa_auth->addr, 6,
 		       mdie, mdie_len, ftie, ftie_len,
 		       rsnie, rsnie_len,
 		       ric_start, ric_start ? pos - ric_start : 0,
@@ -789,7 +787,7 @@
 	 * optimized by adding the STA entry earlier.
 	 */
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk1, klen))
+			     sm->PTK.tk, klen))
 		return;
 
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -807,7 +805,7 @@
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	struct wpa_auth_config *conf;
 	struct wpa_ft_ies parse;
-	size_t buflen, ptk_len;
+	size_t buflen;
 	int ret;
 	u8 *pos, *end;
 	int pairwise;
@@ -892,13 +890,11 @@
 	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
 		    sm->ANonce, WPA_NONCE_LEN);
 
-	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);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
-			(u8 *) &sm->PTK, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+	if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+			      sm->wpa_auth->addr, pmk_r1_name,
+			      &sm->PTK, ptk_name, sm->wpa_key_mgmt,
+			      pairwise) < 0)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
 	sm->pairwise = pairwise;
 	sm->PTK_valid = TRUE;
@@ -993,7 +989,8 @@
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
 	struct rsn_ftie *ftie;
-	u8 mic[16];
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+	size_t mic_len = 16;
 	unsigned int count;
 
 	if (sm == NULL)
@@ -1108,7 +1105,8 @@
 		return -1;
 	}
 
-	if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+	if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+		       sm->wpa_auth->addr, 5,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2,
@@ -1118,12 +1116,13 @@
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
-	if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+	if (os_memcmp_const(mic, ftie->mic, mic_len) != 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: Received MIC",
+			    ftie->mic, mic_len);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
 		wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
 			    parse.mdie - 2, parse.mdie_len + 2);
 		wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 5433d70..59a56e8 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/sae.h"
+#include "common/wpa_ctrl.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eap_server/eap.h"
@@ -53,8 +54,8 @@
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
 	wconf->ssid_len = conf->ssid.ssid_len;
-	if (wconf->ssid_len > SSID_LEN)
-		wconf->ssid_len = SSID_LEN;
+	if (wconf->ssid_len > SSID_MAX_LEN)
+		wconf->ssid_len = SSID_MAX_LEN;
 	os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
 	os_memcpy(wconf->mobility_domain, conf->mobility_domain,
 		  MOBILITY_DOMAIN_ID_LEN);
@@ -144,6 +145,14 @@
 }
 
 
+static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
+		MAC2STR(addr));
+}
+
+
 static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
 				       wpa_eapol_variable var, int value)
 {
@@ -249,12 +258,17 @@
 	struct sta_info *sta;
 
 	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL)
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA");
 		return -1;
+	}
 
 	key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
-	if (key == NULL)
+	if (key == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p",
+			   sta->eapol_sm);
 		return -1;
+	}
 
 	if (keylen > *len)
 		keylen = *len;
@@ -574,6 +588,7 @@
 	cb.logger = hostapd_wpa_auth_logger;
 	cb.disconnect = hostapd_wpa_auth_disconnect;
 	cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+	cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
 	cb.set_eapol = hostapd_wpa_auth_set_eapol;
 	cb.get_eapol = hostapd_wpa_auth_get_eapol;
 	cb.get_psk = hostapd_wpa_auth_get_psk;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 478bc95..7b2cd3e 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -248,7 +248,7 @@
 		   u8 *buf, size_t len, const u8 *subelem,
 		   size_t subelem_len);
 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
-			   struct wpa_ptk *ptk, size_t ptk_len);
+			   struct wpa_ptk *ptk);
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
 void wpa_ft_install_ptk(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index c926765..f287297 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -205,6 +205,11 @@
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
 
 #ifdef CONFIG_RSN_TESTING
 	if (rsn_testing) {
@@ -482,6 +487,8 @@
 		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		if (0) {
 		}
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
 			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
 #ifdef CONFIG_IEEE80211R
@@ -562,6 +569,8 @@
 	}
 	if (0) {
 	}
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 #ifdef CONFIG_IEEE80211R
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 9ba7aba..68eaeca 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -324,7 +324,7 @@
 	wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
 
 	bss->wps_state = 2;
-	if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+	if (cred->ssid_len <= SSID_MAX_LEN) {
 		os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
 		bss->ssid.ssid_len = cred->ssid_len;
 		bss->ssid.ssid_set = 1;
@@ -362,10 +362,9 @@
 			if (bss->ssid.wpa_passphrase)
 				os_memcpy(bss->ssid.wpa_passphrase, cred->key,
 					  cred->key_len);
-			os_free(bss->ssid.wpa_psk);
-			bss->ssid.wpa_psk = NULL;
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 		} else if (cred->key_len == 64) {
-			os_free(bss->ssid.wpa_psk);
+			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
 			bss->ssid.wpa_psk =
 				os_zalloc(sizeof(struct hostapd_wpa_psk));
 			if (bss->ssid.wpa_psk &&
@@ -857,8 +856,10 @@
 	wpabuf_free(hapd->wps_probe_resp_ie);
 	hapd->wps_probe_resp_ie = NULL;
 
-	if (deinit_only)
+	if (deinit_only) {
+		hostapd_reset_ap_wps_ie(hapd);
 		return;
+	}
 
 	hostapd_set_ap_wps_ie(hapd);
 }
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
index 8f77015..aef9a53 100644
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -51,6 +51,14 @@
 		return -1;
 	}
 
+#ifdef CONFIG_IPV6
+	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to enable multicast snooping on the bridge");
+		return -1;
+	}
+#endif /* CONFIG_IPV6 */
+
 	return 0;
 }
 
diff --git a/src/common/Makefile b/src/common/Makefile
index adfd3df..e703630 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,8 +1,28 @@
-all:
-	@echo Nothing to be made.
+all: libcommon.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_SAE
+CFLAGS += -DCONFIG_SUITE
+CFLAGS += -DCONFIG_SUITEB
+
+LIB_OBJS= \
+	gas.o \
+	hw_features_common.o \
+	ieee802_11_common.o \
+	sae.o \
+	wpa_common.o
+
+libcommon.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/common/defs.h b/src/common/defs.h
index e1bbd50..24f80ad 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -50,6 +50,7 @@
 #define WPA_KEY_MGMT_CCKM BIT(14)
 #define WPA_KEY_MGMT_OSEN BIT(15)
 #define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
@@ -58,7 +59,8 @@
 			 WPA_KEY_MGMT_CCKM |
 			 WPA_KEY_MGMT_OSEN |
 			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
 }
 
 static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -91,9 +93,15 @@
 			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
 }
 
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+	return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
 static inline int wpa_key_mgmt_suite_b(int akm)
 {
-	return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B);
+	return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
 }
 
 static inline int wpa_key_mgmt_wpa(int akm)
@@ -302,23 +310,13 @@
 	WPA_CTRL_REQ_EAP_OTP,
 	WPA_CTRL_REQ_EAP_PASSPHRASE,
 	WPA_CTRL_REQ_SIM,
+	WPA_CTRL_REQ_PSK_PASSPHRASE,
 	NUM_WPA_CTRL_REQS
 };
 
 /* Maximum number of EAP methods to store for EAP server user information */
 #define EAP_MAX_METHODS 8
 
-/**
- * enum ht_mode - channel width and offset
- */
-enum ht_mode {
-	CHAN_UNDEFINED = 0,
-	CHAN_NO_HT,
-	CHAN_HT20,
-	CHAN_HT40PLUS,
-	CHAN_HT40MINUS,
-};
-
 enum mesh_plink_state {
 	PLINK_LISTEN = 1,
 	PLINK_OPEN_SENT,
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
new file mode 100644
index 0000000..e61f824
--- /dev/null
+++ b/src/common/hw_features_common.c
@@ -0,0 +1,461 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, 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 "defs.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+#include "hw_features_common.h"
+
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+						  int chan, int *freq)
+{
+	int i;
+
+	if (freq)
+		*freq = 0;
+
+	if (!mode)
+		return NULL;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *ch = &mode->channels[i];
+		if (ch->chan == chan) {
+			if (freq)
+				*freq = ch->freq;
+			return ch;
+		}
+	}
+
+	return NULL;
+}
+
+
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+						  int freq, int *chan)
+{
+	int i;
+
+	if (chan)
+		*chan = 0;
+
+	if (!mode)
+		return NULL;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *ch = &mode->channels[i];
+		if (ch->freq == freq) {
+			if (chan)
+				*chan = ch->chan;
+			return ch;
+		}
+	}
+
+	return NULL;
+}
+
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
+{
+	int freq;
+
+	hw_get_channel_chan(mode, chan, &freq);
+
+	return freq;
+}
+
+
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+{
+	int chan;
+
+	hw_get_channel_freq(mode, freq, &chan);
+
+	return chan;
+}
+
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+			      int sec_chan)
+{
+	int ok, j, first;
+	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
+			  149, 157, 184, 192 };
+	size_t k;
+
+	if (pri_chan == sec_chan || !sec_chan)
+		return 1; /* HT40 not used */
+
+	wpa_printf(MSG_DEBUG,
+		   "HT40: control channel: %d  secondary channel: %d",
+		   pri_chan, sec_chan);
+
+	/* Verify that HT40 secondary channel is an allowed 20 MHz
+	 * channel */
+	ok = 0;
+	for (j = 0; j < mode->num_channels; j++) {
+		struct hostapd_channel_data *chan = &mode->channels[j];
+		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+		    chan->chan == sec_chan) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+			   sec_chan);
+		return 0;
+	}
+
+	/*
+	 * Verify that HT40 primary,secondary channel pair is allowed per
+	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+	 * 2.4 GHz rules allow all cases where the secondary channel fits into
+	 * the list of allowed channels (already checked above).
+	 */
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 1;
+
+	first = pri_chan < sec_chan ? pri_chan : sec_chan;
+
+	ok = 0;
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+		if (first == allowed[k]) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+			   pri_chan, sec_chan);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
+{
+	struct ieee80211_ht_operation *oper;
+	struct ieee802_11_elems elems;
+
+	*pri_chan = *sec_chan = 0;
+
+	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+	if (elems.ht_operation) {
+		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+		*pri_chan = oper->primary_chan;
+		if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
+			int sec = oper->ht_param &
+				HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+			if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+				*sec_chan = *pri_chan + 4;
+			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+				*sec_chan = *pri_chan - 4;
+		}
+	}
+}
+
+
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+		   struct wpa_scan_results *scan_res, int pri_chan,
+		   int sec_chan)
+{
+	int pri_freq, sec_freq, pri_bss, sec_bss;
+	int bss_pri_chan, bss_sec_chan;
+	size_t i;
+	int match;
+
+	if (!mode || !scan_res || !pri_chan || !sec_chan)
+		return 0;
+
+	if (pri_chan == sec_chan)
+		return 0;
+
+	pri_freq = hw_get_freq(mode, pri_chan);
+	sec_freq = hw_get_freq(mode, sec_chan);
+
+	/*
+	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
+	 * channel, but not on selected PRI channel.
+	 */
+	pri_bss = sec_bss = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		if (bss->freq == pri_freq)
+			pri_bss++;
+		else if (bss->freq == sec_freq)
+			sec_bss++;
+	}
+	if (sec_bss && !pri_bss) {
+		wpa_printf(MSG_INFO,
+			   "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes");
+		return 2;
+	}
+
+	/*
+	 * Match PRI/SEC channel with any existing HT40 BSS on the same
+	 * channels that we are about to use (if already mixed order in
+	 * existing BSSes, use own preference).
+	 */
+	match = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+		if (pri_chan == bss_pri_chan &&
+		    sec_chan == bss_sec_chan) {
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {
+		for (i = 0; i < scan_res->num; i++) {
+			struct wpa_scan_res *bss = scan_res->res[i];
+			get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+			if (pri_chan == bss_sec_chan &&
+			    sec_chan == bss_pri_chan) {
+				wpa_printf(MSG_INFO, "Switch own primary and "
+					   "secondary channel due to BSS "
+					   "overlap with " MACSTR,
+					   MAC2STR(bss->bssid));
+				return 2;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
+{
+	struct ieee802_11_elems elems;
+	struct ieee80211_ht_operation *oper;
+
+	if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
+		return 0;
+
+	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+	if (!elems.ht_capabilities) {
+		wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
+			   MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+		return 1;
+	}
+
+	if (elems.ht_operation) {
+		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+		if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
+			return 0;
+
+		wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
+			   MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+		return 1;
+	}
+	return 0;
+}
+
+
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+		    struct wpa_scan_results *scan_res, int pri_chan,
+		    int sec_chan)
+{
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	size_t i;
+
+	if (!mode || !scan_res || !pri_chan || !sec_chan)
+		return 0;
+
+	if (pri_chan == sec_chan)
+		return 0;
+
+	pri_freq = hw_get_freq(mode, pri_chan);
+	sec_freq = hw_get_freq(mode, sec_chan);
+
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		int pri = bss->freq;
+		int sec = pri;
+		struct ieee802_11_elems elems;
+
+		/* Check for overlapping 20 MHz BSS */
+		if (check_20mhz_bss(bss, pri_freq, affected_start,
+				    affected_end)) {
+			wpa_printf(MSG_DEBUG,
+				   "Overlapping 20 MHz BSS is found");
+			return 0;
+		}
+
+		get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+		if (sec_chan) {
+			if (sec_chan < pri_chan)
+				sec = pri - 20;
+			else
+				sec = pri + 20;
+		}
+
+		if ((pri < affected_start || pri > affected_end) &&
+		    (sec < affected_start || sec > affected_end))
+			continue; /* not within affected channel range */
+
+		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+			   " freq=%d pri=%d sec=%d",
+			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+		if (sec_chan) {
+			if (pri_freq != pri || sec_freq != sec) {
+				wpa_printf(MSG_DEBUG,
+					   "40 MHz pri/sec mismatch with BSS "
+					   MACSTR
+					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+					   MAC2STR(bss->bssid),
+					   pri, sec, pri_chan,
+					   sec > pri ? '+' : '-',
+					   pri_freq, sec_freq);
+				return 0;
+			}
+		}
+
+		ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+				       0);
+		if (elems.ht_capabilities) {
+			struct ieee80211_ht_capabilities *ht_cap =
+				(struct ieee80211_ht_capabilities *)
+				elems.ht_capabilities;
+
+			if (le_to_host16(ht_cap->ht_capabilities_info) &
+			    HT_CAP_INFO_40MHZ_INTOLERANT) {
+				wpa_printf(MSG_DEBUG,
+					   "40 MHz Intolerant is set on channel %d in BSS "
+					   MACSTR, pri, MAC2STR(bss->bssid));
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+			    enum hostapd_hw_mode mode,
+			    int freq, int channel, int ht_enabled,
+			    int vht_enabled, int sec_channel_offset,
+			    int vht_oper_chwidth, int center_segment0,
+			    int center_segment1, u32 vht_caps)
+{
+	os_memset(data, 0, sizeof(*data));
+	data->mode = mode;
+	data->freq = freq;
+	data->channel = channel;
+	data->ht_enabled = ht_enabled;
+	data->vht_enabled = vht_enabled;
+	data->sec_channel_offset = sec_channel_offset;
+	data->center_freq1 = freq + sec_channel_offset * 10;
+	data->center_freq2 = 0;
+	data->bandwidth = sec_channel_offset ? 40 : 20;
+
+	if (data->vht_enabled) switch (vht_oper_chwidth) {
+	case VHT_CHANWIDTH_USE_HT:
+		if (center_segment1)
+			return -1;
+		if (center_segment0 != 0 &&
+		    5000 + center_segment0 * 5 != data->center_freq1 &&
+		    2407 + center_segment0 * 5 != data->center_freq1)
+			return -1;
+		break;
+	case VHT_CHANWIDTH_80P80MHZ:
+		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+			wpa_printf(MSG_ERROR,
+				   "80+80 channel width is not supported!");
+			return -1;
+		}
+		if (center_segment1 == center_segment0 + 4 ||
+		    center_segment1 == center_segment0 - 4)
+			return -1;
+		data->center_freq2 = 5000 + center_segment1 * 5;
+		/* fall through */
+	case VHT_CHANWIDTH_80MHZ:
+		data->bandwidth = 80;
+		if (vht_oper_chwidth == 1 && center_segment1)
+			return -1;
+		if (vht_oper_chwidth == 3 && !center_segment1)
+			return -1;
+		if (!sec_channel_offset)
+			return -1;
+		if (!center_segment0) {
+			if (channel <= 48)
+				center_segment0 = 42;
+			else if (channel <= 64)
+				center_segment0 = 58;
+			else if (channel <= 112)
+				center_segment0 = 106;
+			else if (channel <= 128)
+				center_segment0 = 122;
+			else if (channel <= 144)
+				center_segment0 = 138;
+			else if (channel <= 161)
+				center_segment0 = 155;
+			data->center_freq1 = 5000 + center_segment0 * 5;
+		} else {
+			/*
+			 * Note: HT/VHT config and params are coupled. Check if
+			 * HT40 channel band is in VHT80 Pri channel band
+			 * configuration.
+			 */
+			if (center_segment0 == channel + 6 ||
+			    center_segment0 == channel + 2 ||
+			    center_segment0 == channel - 2 ||
+			    center_segment0 == channel - 6)
+				data->center_freq1 = 5000 + center_segment0 * 5;
+			else
+				return -1;
+		}
+		break;
+	case VHT_CHANWIDTH_160MHZ:
+		data->bandwidth = 160;
+		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+			wpa_printf(MSG_ERROR,
+				   "160MHZ channel width is not supported!");
+			return -1;
+		}
+		if (center_segment1)
+			return -1;
+		if (!sec_channel_offset)
+			return -1;
+		/*
+		 * Note: HT/VHT config and params are coupled. Check if
+		 * HT40 channel band is in VHT160 channel band configuration.
+		 */
+		if (center_segment0 == channel + 14 ||
+		    center_segment0 == channel + 10 ||
+		    center_segment0 == channel + 6 ||
+		    center_segment0 == channel + 2 ||
+		    center_segment0 == channel - 2 ||
+		    center_segment0 == channel - 6 ||
+		    center_segment0 == channel - 10 ||
+		    center_segment0 == channel - 14)
+			data->center_freq1 = 5000 + center_segment0 * 5;
+		else
+			return -1;
+		break;
+	}
+
+	return 0;
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
new file mode 100644
index 0000000..7f43d00
--- /dev/null
+++ b/src/common/hw_features_common.h
@@ -0,0 +1,40 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HW_FEATURES_COMMON_H
+#define HW_FEATURES_COMMON_H
+
+#include "drivers/driver.h"
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+						  int chan, int *freq);
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+						  int freq, int *chan);
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+			      int sec_chan);
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+		   struct wpa_scan_results *scan_res, int pri_chan,
+		   int sec_chan);
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+		    struct wpa_scan_results *scan_res, int pri_chan,
+		    int sec_chan);
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+			    enum hostapd_hw_mode mode,
+			    int freq, int channel, int ht_enabled,
+			    int vht_enabled, int sec_channel_offset,
+			    int vht_oper_chwidth, int center_segment0,
+			    int center_segment1, u32 vht_caps);
+
+#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e1d45cf..7843e6f 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "defs.h"
+#include "wpa_common.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
 
@@ -128,6 +129,15 @@
 			elems->vendor_ht_cap = pos;
 			elems->vendor_ht_cap_len = elen;
 			break;
+		case VENDOR_VHT_TYPE:
+			if (elen > 4 &&
+			    (pos[4] == VENDOR_VHT_SUBTYPE ||
+			     pos[4] == VENDOR_VHT_SUBTYPE2)) {
+				elems->vendor_vht = pos;
+				elems->vendor_vht_len = elen;
+			} else
+				return -1;
+			break;
 		default:
 			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
 				   "information element ignored "
@@ -187,6 +197,12 @@
 
 		switch (id) {
 		case WLAN_EID_SSID:
+			if (elen > SSID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG,
+					   "Ignored too long SSID element (elen=%u)",
+					   elen);
+				break;
+			}
 			elems->ssid = pos;
 			elems->ssid_len = elen;
 			break;
@@ -195,8 +211,9 @@
 			elems->supp_rates_len = elen;
 			break;
 		case WLAN_EID_DS_PARAMS:
+			if (elen < 1)
+				break;
 			elems->ds_params = pos;
-			elems->ds_params_len = elen;
 			break;
 		case WLAN_EID_CF_PARAMS:
 		case WLAN_EID_TIM:
@@ -206,8 +223,9 @@
 			elems->challenge_len = elen;
 			break;
 		case WLAN_EID_ERP_INFO:
+			if (elen < 1)
+				break;
 			elems->erp_info = pos;
-			elems->erp_info_len = elen;
 			break;
 		case WLAN_EID_EXT_SUPP_RATES:
 			elems->ext_supp_rates = pos;
@@ -230,24 +248,31 @@
 			elems->supp_channels_len = elen;
 			break;
 		case WLAN_EID_MOBILITY_DOMAIN:
+			if (elen < sizeof(struct rsn_mdie))
+				break;
 			elems->mdie = pos;
 			elems->mdie_len = elen;
 			break;
 		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (elen < sizeof(struct rsn_ftie))
+				break;
 			elems->ftie = pos;
 			elems->ftie_len = elen;
 			break;
 		case WLAN_EID_TIMEOUT_INTERVAL:
+			if (elen != 5)
+				break;
 			elems->timeout_int = pos;
-			elems->timeout_int_len = elen;
 			break;
 		case WLAN_EID_HT_CAP:
+			if (elen < sizeof(struct ieee80211_ht_capabilities))
+				break;
 			elems->ht_capabilities = pos;
-			elems->ht_capabilities_len = elen;
 			break;
 		case WLAN_EID_HT_OPERATION:
+			if (elen < sizeof(struct ieee80211_ht_operation))
+				break;
 			elems->ht_operation = pos;
-			elems->ht_operation_len = elen;
 			break;
 		case WLAN_EID_MESH_CONFIG:
 			elems->mesh_config = pos;
@@ -262,12 +287,14 @@
 			elems->peer_mgmt_len = elen;
 			break;
 		case WLAN_EID_VHT_CAP:
+			if (elen < sizeof(struct ieee80211_vht_capabilities))
+				break;
 			elems->vht_capabilities = pos;
-			elems->vht_capabilities_len = elen;
 			break;
 		case WLAN_EID_VHT_OPERATION:
+			if (elen < sizeof(struct ieee80211_vht_operation))
+				break;
 			elems->vht_operation = pos;
-			elems->vht_operation_len = elen;
 			break;
 		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
 			if (elen != 1)
@@ -817,6 +844,13 @@
 }
 
 
+int ieee80211_is_dfs(int freq)
+{
+	/* TODO: this could be more accurate to better cover all domains */
+	return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+}
+
+
 static int is_11b(u8 rate)
 {
 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2357afc..c84d8a7 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -35,6 +35,7 @@
 	const u8 *vht_operation;
 	const u8 *vht_opmode_notif;
 	const u8 *vendor_ht_cap;
+	const u8 *vendor_vht;
 	const u8 *p2p;
 	const u8 *wfd;
 	const u8 *link_id;
@@ -50,9 +51,7 @@
 
 	u8 ssid_len;
 	u8 supp_rates_len;
-	u8 ds_params_len;
 	u8 challenge_len;
-	u8 erp_info_len;
 	u8 ext_supp_rates_len;
 	u8 wpa_ie_len;
 	u8 rsn_ie_len;
@@ -62,15 +61,11 @@
 	u8 supp_channels_len;
 	u8 mdie_len;
 	u8 ftie_len;
-	u8 timeout_int_len;
-	u8 ht_capabilities_len;
-	u8 ht_operation_len;
 	u8 mesh_config_len;
 	u8 mesh_id_len;
 	u8 peer_mgmt_len;
-	u8 vht_capabilities_len;
-	u8 vht_operation_len;
 	u8 vendor_ht_cap_len;
+	u8 vendor_vht_len;
 	u8 p2p_len;
 	u8 wfd_len;
 	u8 interworking_len;
@@ -106,6 +101,7 @@
 			  const char *name, const char *val);
 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+int ieee80211_is_dfs(int freq);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
 
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 0ce5daf..feab921 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007-2008 Intel Corporation
  *
  * This software may be distributed under the terms of the BSD license.
@@ -10,6 +10,8 @@
 #ifndef IEEE802_11_DEFS_H
 #define IEEE802_11_DEFS_H
 
+#include <utils/common.h>
+
 /* IEEE 802.11 defines */
 
 #define WLAN_FC_PVER		0x0003
@@ -470,35 +472,35 @@
 			le16 auth_transaction;
 			le16 status_code;
 			/* possibly followed by Challenge text */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED auth;
 		struct {
 			le16 reason_code;
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED deauth;
 		struct {
 			le16 capab_info;
 			le16 listen_interval;
 			/* followed by SSID and Supported rates */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED assoc_req;
 		struct {
 			le16 capab_info;
 			le16 status_code;
 			le16 aid;
 			/* followed by Supported rates */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED assoc_resp, reassoc_resp;
 		struct {
 			le16 capab_info;
 			le16 listen_interval;
 			u8 current_ap[6];
 			/* followed by SSID and Supported rates */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED reassoc_req;
 		struct {
 			le16 reason_code;
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED disassoc;
 		struct {
 			u8 timestamp[8];
@@ -506,7 +508,7 @@
 			le16 capab_info;
 			/* followed by some of SSID, Supported rates,
 			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED beacon;
 		struct {
 			/* only variable items: SSID, Supported rates */
@@ -518,7 +520,7 @@
 			le16 capab_info;
 			/* followed by some of SSID, Supported rates,
 			 * FH Params, DS Params, CF Params, IBSS Params */
-			u8 variable[0];
+			u8 variable[];
 		} STRUCT_PACKED probe_resp;
 		struct {
 			u8 category;
@@ -527,7 +529,7 @@
 					u8 action_code;
 					u8 dialog_token;
 					u8 status_code;
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED wmm_action;
 				struct{
 					u8 action_code;
@@ -541,14 +543,14 @@
 					u8 action;
 					u8 sta_addr[ETH_ALEN];
 					u8 target_ap_addr[ETH_ALEN];
-					u8 variable[0]; /* FT Request */
+					u8 variable[]; /* FT Request */
 				} STRUCT_PACKED ft_action_req;
 				struct {
 					u8 action;
 					u8 sta_addr[ETH_ALEN];
 					u8 target_ap_addr[ETH_ALEN];
 					le16 status_code;
-					u8 variable[0]; /* FT Request */
+					u8 variable[]; /* FT Request */
 				} STRUCT_PACKED ft_action_resp;
 				struct {
 					u8 action;
@@ -561,23 +563,23 @@
 				struct {
 					u8 action;
 					u8 dialogtoken;
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED wnm_sleep_req;
 				struct {
 					u8 action;
 					u8 dialogtoken;
 					le16 keydata_len;
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED wnm_sleep_resp;
 				struct {
 					u8 action;
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED public_action;
 				struct {
 					u8 action; /* 9 */
 					u8 oui[3];
 					/* Vendor-specific content */
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED vs_public_action;
 				struct {
 					u8 action; /* 7 */
@@ -589,7 +591,7 @@
 					 * Session Information URL (optional),
 					 * BSS Transition Candidate List
 					 * Entries */
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED bss_tm_req;
 				struct {
 					u8 action; /* 8 */
@@ -599,7 +601,7 @@
 					/* Target BSSID (optional),
 					 * BSS Transition Candidate List
 					 * Entries (optional) */
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED bss_tm_resp;
 				struct {
 					u8 action; /* 6 */
@@ -607,11 +609,11 @@
 					u8 query_reason;
 					/* BSS Transition Candidate List
 					 * Entries (optional) */
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED bss_tm_query;
 				struct {
 					u8 action; /* 15 */
-					u8 variable[0];
+					u8 variable[];
 				} STRUCT_PACKED slf_prot_action;
 				struct {
 					u8 action; /* 5 */
@@ -1039,6 +1041,14 @@
 	P2P_ATTR_OPERATING_CHANNEL = 17,
 	P2P_ATTR_INVITATION_FLAGS = 18,
 	P2P_ATTR_OOB_GO_NEG_CHANNEL = 19,
+	P2P_ATTR_SERVICE_HASH = 21,
+	P2P_ATTR_SESSION_INFORMATION_DATA = 22,
+	P2P_ATTR_CONNECTION_CAPABILITY = 23,
+	P2P_ATTR_ADVERTISEMENT_ID = 24,
+	P2P_ATTR_ADVERTISED_SERVICE = 25,
+	P2P_ATTR_SESSION_ID = 26,
+	P2P_ATTR_FEATURE_CAPABILITY = 27,
+	P2P_ATTR_PERSISTENT_GROUP = 28,
 	P2P_ATTR_VENDOR_SPECIFIC = 221
 };
 
@@ -1083,6 +1093,7 @@
 	P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
 	P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
 	P2P_SC_FAIL_REJECTED_BY_USER = 11,
+	P2P_SC_SUCCESS_DEFERRED = 12,
 };
 
 enum p2p_role_indication {
@@ -1121,6 +1132,7 @@
 	P2P_SERV_UPNP = 2,
 	P2P_SERV_WS_DISCOVERY = 3,
 	P2P_SERV_WIFI_DISPLAY = 4,
+	P2P_SERV_P2PS = 11,
 	P2P_SERV_VENDOR_SPECIFIC = 255
 };
 
@@ -1160,6 +1172,9 @@
 };
 
 #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE		0x04
+#define VENDOR_VHT_SUBTYPE	0x08
+#define VENDOR_VHT_SUBTYPE2	0x00
 
 #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
 
@@ -1194,6 +1209,7 @@
 #define WLAN_AKM_SUITE_8021X_SHA256	0x000FAC05
 #define WLAN_AKM_SUITE_PSK_SHA256	0x000FAC06
 #define WLAN_AKM_SUITE_8021X_SUITE_B	0x000FAC11
+#define WLAN_AKM_SUITE_8021X_SUITE_B_192	0x000FAC12
 #define WLAN_AKM_SUITE_CCKM		0x00409600
 #define WLAN_AKM_SUITE_OSEN		0x506f9a01
 
@@ -1357,4 +1373,6 @@
 	u8 variable[0];
 } STRUCT_PACKED;
 
+#define SSID_MAX_LEN 32
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 4dc34c4..c6a472d 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -9,6 +9,8 @@
 #ifndef PRIVSEP_COMMANDS_H
 #define PRIVSEP_COMMANDS_H
 
+#include "common/ieee802_11_defs.h"
+
 enum privsep_cmd {
 	PRIVSEP_CMD_REGISTER,
 	PRIVSEP_CMD_UNREGISTER,
@@ -29,7 +31,7 @@
 struct privsep_cmd_associate
 {
 	u8 bssid[ETH_ALEN];
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	int hwmode;
 	int freq;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ec1be86..e51f85f 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,6 @@
 /*
  * Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -69,6 +69,26 @@
  * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
  *	supported by the driver. enum qca_wlan_vendor_features defines
  *	the possible features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver,
+ *	which supports DFS offloading, to indicate a channel availability check
+ *	start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Event used by driver,
+ *	which supports DFS offloading, to indicate a channel availability check
+ *	completion.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Event used by driver,
+ *	which supports DFS offloading, to indicate that the channel availability
+ *	check aborted, no change to the channel status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Event used by
+ *	driver, which supports DFS offloading, to indicate that the
+ *	Non-Occupancy Period for this channel is over, channel becomes usable.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
+ *	which supports DFS offloading, to indicate a radar pattern has been
+ *	detected. The channel is now unusable.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -112,9 +132,25 @@
 	QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
 	QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
 	QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
-	/* 53 - reserved for QCA */
+	/* 53 - reserved - was used by QCA, but not in use anymore */
 	QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
 	QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
+	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
+	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57,
+	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
+	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
+	QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
+	/* 61-90 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
+	QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
+	QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
+	QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94,
+	QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95,
+	QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96,
+	QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97,
+	QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98,
+	QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
+	QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
 };
 
 
@@ -134,6 +170,7 @@
 	QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
 	QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
+	QCA_WLAN_VENDOR_ATTR_TEST = 8,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_MAX	= QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -167,6 +204,11 @@
 	QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
 	QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
 	QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
+	QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+	QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_ACS_MAX =
@@ -194,4 +236,25 @@
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
+/**
+ * enum qca_wlan_vendor_attr_data_offload_ind - Vendor Data Offload Indication
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION: Session corresponding to
+ *	the offloaded data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL: Protocol of the offloaded
+ *	data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT: Event type for the data offload
+ *	indication.
+ */
+enum qca_wlan_vendor_attr_data_offload_ind {
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION,
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL,
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
+	QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
+};
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.h b/src/common/sae.h
index 89d74ab..3ebf40c 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -44,6 +44,7 @@
 	u8 pmk[SAE_PMK_LEN];
 	struct crypto_bignum *peer_commit_scalar;
 	int group;
+	int sync;
 	struct sae_temporary_data *tmp;
 };
 
diff --git a/src/common/version.h b/src/common/version.h
index c662270..5ddf617 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
 #define VERSION_STR_POSTFIX ""
 #endif /* VERSION_STR_POSTFIX */
 
-#define VERSION_STR "2.4-devel" VERSION_STR_POSTFIX
+#define VERSION_STR "2.5-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a573e11..a0747b4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
 /*
  * WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,7 @@
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
 #include "ieee802_11_defs.h"
@@ -19,9 +20,34 @@
 #include "wpa_common.h"
 
 
+static unsigned int wpa_kck_len(int akmp)
+{
+	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		return 24;
+	return 16;
+}
+
+
+static unsigned int wpa_kek_len(int akmp)
+{
+	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		return 32;
+	return 16;
+}
+
+
+unsigned int wpa_mic_len(int akmp)
+{
+	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		return 24;
+	return 16;
+}
+
+
 /**
  * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
  * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @key_len: KCK length in octets
  * @akmp: WPA_KEY_MGMT_* used in key derivation
  * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
  * @buf: Pointer to the beginning of the EAPOL header (version field)
@@ -38,18 +64,18 @@
  * happened during final editing of the standard and the correct behavior is
  * defined in the last draft (IEEE 802.11i/D10).
  */
-int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
-		      size_t len, u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+		      const u8 *buf, size_t len, u8 *mic)
 {
-	u8 hash[SHA256_MAC_LEN];
+	u8 hash[SHA384_MAC_LEN];
 
 	switch (ver) {
 #ifndef CONFIG_FIPS
 	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
-		return hmac_md5(key, 16, buf, len, mic);
+		return hmac_md5(key, key_len, buf, len, mic);
 #endif /* CONFIG_FIPS */
 	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
-		if (hmac_sha1(key, 16, buf, len, hash))
+		if (hmac_sha1(key, key_len, buf, len, hash))
 			return -1;
 		os_memcpy(mic, hash, MD5_MAC_LEN);
 		break;
@@ -65,11 +91,18 @@
 #endif /* CONFIG_HS20 */
 #ifdef CONFIG_SUITEB
 		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
-			if (hmac_sha256(key, 16, buf, len, hash))
+			if (hmac_sha256(key, key_len, buf, len, hash))
 				return -1;
 			os_memcpy(mic, hash, MD5_MAC_LEN);
 			break;
 #endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+			if (hmac_sha384(key, key_len, buf, len, hash))
+				return -1;
+			os_memcpy(mic, hash, 24);
+			break;
+#endif /* CONFIG_SUITEB192 */
 		default:
 			return -1;
 		}
@@ -92,8 +125,9 @@
  * @nonce1: ANonce or SNonce
  * @nonce2: SNonce or ANonce
  * @ptk: Buffer for pairwise transient key
- * @ptk_len: Length of PTK
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
  *
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -104,12 +138,14 @@
  *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
  *             Min(INonce, PNonce) || Max(INonce, PNonce))
  */
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
-		    const u8 *addr1, const u8 *addr2,
-		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len, int use_sha256)
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		   const u8 *addr1, const u8 *addr2,
+		   const u8 *nonce1, const u8 *nonce2,
+		   struct wpa_ptk *ptk, int akmp, int cipher)
 {
 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+	size_t ptk_len;
 
 	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
 		os_memcpy(data, addr1, ETH_ALEN);
@@ -129,76 +165,111 @@
 			  WPA_NONCE_LEN);
 	}
 
+	ptk->kck_len = wpa_kck_len(akmp);
+	ptk->kek_len = wpa_kek_len(akmp);
+	ptk->tk_len = wpa_cipher_key_len(cipher);
+	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
 #ifdef CONFIG_IEEE80211W
-	if (use_sha256)
+	if (wpa_key_mgmt_sha256(akmp))
 		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
-			   ptk, ptk_len);
+			   tmp, ptk_len);
 	else
 #endif /* CONFIG_IEEE80211W */
-		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
-			 ptk_len);
+		sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
 
 	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
 		   MAC2STR(addr1), MAC2STR(addr2));
 	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
 	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
-	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
+
+	os_memcpy(ptk->kck, tmp, ptk->kck_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+
+	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+
+	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+
+	os_memset(tmp, 0, sizeof(tmp));
+	return 0;
 }
 
 
 #ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
-	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+	       const u8 *ap_addr, u8 transaction_seqnum,
+	       const u8 *mdie, size_t mdie_len,
 	       const u8 *ftie, size_t ftie_len,
 	       const u8 *rsnie, size_t rsnie_len,
 	       const u8 *ric, size_t ric_len, u8 *mic)
 {
-	u8 *buf, *pos;
-	size_t buf_len;
+	const u8 *addr[9];
+	size_t len[9];
+	size_t i, num_elem = 0;
+	u8 zero_mic[16];
 
-	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
-	buf = os_malloc(buf_len);
-	if (buf == NULL)
+	if (kck_len != 16) {
+		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+			   (unsigned int) kck_len);
 		return -1;
+	}
 
-	pos = buf;
-	os_memcpy(pos, sta_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, ap_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	*pos++ = transaction_seqnum;
+	addr[num_elem] = sta_addr;
+	len[num_elem] = ETH_ALEN;
+	num_elem++;
+
+	addr[num_elem] = ap_addr;
+	len[num_elem] = ETH_ALEN;
+	num_elem++;
+
+	addr[num_elem] = &transaction_seqnum;
+	len[num_elem] = 1;
+	num_elem++;
+
 	if (rsnie) {
-		os_memcpy(pos, rsnie, rsnie_len);
-		pos += rsnie_len;
+		addr[num_elem] = rsnie;
+		len[num_elem] = rsnie_len;
+		num_elem++;
 	}
 	if (mdie) {
-		os_memcpy(pos, mdie, mdie_len);
-		pos += mdie_len;
+		addr[num_elem] = mdie;
+		len[num_elem] = mdie_len;
+		num_elem++;
 	}
 	if (ftie) {
-		struct rsn_ftie *_ftie;
-		os_memcpy(pos, ftie, ftie_len);
-		if (ftie_len < 2 + sizeof(*_ftie)) {
-			os_free(buf);
+		if (ftie_len < 2 + sizeof(struct rsn_ftie))
 			return -1;
-		}
-		_ftie = (struct rsn_ftie *) (pos + 2);
-		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
-		pos += ftie_len;
+
+		/* IE hdr and mic_control */
+		addr[num_elem] = ftie;
+		len[num_elem] = 2 + 2;
+		num_elem++;
+
+		/* MIC field with all zeros */
+		os_memset(zero_mic, 0, sizeof(zero_mic));
+		addr[num_elem] = zero_mic;
+		len[num_elem] = sizeof(zero_mic);
+		num_elem++;
+
+		/* Rest of FTIE */
+		addr[num_elem] = ftie + 2 + 2 + 16;
+		len[num_elem] = ftie_len - (2 + 2 + 16);
+		num_elem++;
 	}
 	if (ric) {
-		os_memcpy(pos, ric, ric_len);
-		pos += ric_len;
+		addr[num_elem] = ric;
+		len[num_elem] = ric_len;
+		num_elem++;
 	}
 
-	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
-	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
-		os_free(buf);
+	for (i = 0; i < num_elem; i++)
+		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
+	if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
 		return -1;
-	}
-
-	os_free(buf);
 
 	return 0;
 }
@@ -285,6 +356,8 @@
 				parse->rsn_pmkid = data.pmkid;
 			break;
 		case WLAN_EID_MOBILITY_DOMAIN:
+			if (pos[1] < sizeof(struct rsn_mdie))
+				return -1;
 			parse->mdie = pos + 2;
 			parse->mdie_len = pos[1];
 			break;
@@ -297,6 +370,8 @@
 				return -1;
 			break;
 		case WLAN_EID_TIMEOUT_INTERVAL:
+			if (pos[1] != 5)
+				break;
 			parse->tie = pos + 2;
 			parse->tie_len = pos[1];
 			break;
@@ -413,6 +488,10 @@
 #endif /* CONFIG_SAE */
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
 		return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
+		return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
+		return WPA_KEY_MGMT_OSEN;
 	return 0;
 }
 
@@ -447,7 +526,6 @@
 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 			 struct wpa_ie_data *data)
 {
-	const struct rsn_ie_hdr *hdr;
 	const u8 *pos;
 	int left;
 	int i, count;
@@ -477,19 +555,30 @@
 		return -1;
 	}
 
-	hdr = (const struct rsn_ie_hdr *) rsn_ie;
+	if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
+	    rsn_ie[1] == rsn_ie_len - 2 &&
+	    WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
+		pos = rsn_ie + 6;
+		left = rsn_ie_len - 6;
 
-	if (hdr->elem_id != WLAN_EID_RSN ||
-	    hdr->len != rsn_ie_len - 2 ||
-	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
-		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-			   __func__);
-		return -2;
+		data->proto = WPA_PROTO_OSEN;
+	} else {
+		const struct rsn_ie_hdr *hdr;
+
+		hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+		if (hdr->elem_id != WLAN_EID_RSN ||
+		    hdr->len != rsn_ie_len - 2 ||
+		    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+			wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+				   __func__);
+			return -2;
+		}
+
+		pos = (const u8 *) (hdr + 1);
+		left = rsn_ie_len - sizeof(*hdr);
 	}
 
-	pos = (const u8 *) (hdr + 1);
-	left = rsn_ie_len - sizeof(*hdr);
-
 	if (left >= RSN_SELECTOR_LEN) {
 		data->group_cipher = rsn_selector_to_bitfield(pos);
 		if (!wpa_cipher_valid_group(data->group_cipher)) {
@@ -753,7 +842,7 @@
 		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
 		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
 {
-	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
 	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
 	u8 *pos, r0_key_data[48], hash[32];
 	const u8 *addr[2];
@@ -767,7 +856,7 @@
 	 * PMK-R0 = L(R0-Key-Data, 0, 256)
 	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
 	 */
-	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
 		return;
 	pos = buf;
 	*pos++ = ssid_len;
@@ -858,15 +947,17 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.5
  */
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
-		       const u8 *sta_addr, const u8 *bssid,
-		       const u8 *pmk_r1_name,
-		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		      const u8 *sta_addr, const u8 *bssid,
+		      const u8 *pmk_r1_name,
+		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
 {
 	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
 	u8 *pos, hash[32];
 	const u8 *addr[6];
 	size_t len[6];
+	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+	size_t ptk_len;
 
 	/*
 	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
@@ -882,7 +973,12 @@
 	os_memcpy(pos, sta_addr, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+	ptk->kck_len = wpa_kck_len(akmp);
+	ptk->kek_len = wpa_kek_len(akmp);
+	ptk->tk_len = wpa_cipher_key_len(cipher);
+	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
 
 	/*
 	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -903,6 +999,19 @@
 
 	sha256_vector(6, addr, len, hash);
 	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+
+	os_memcpy(ptk->kck, tmp, ptk->kck_len);
+	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	os_memset(tmp, 0, sizeof(tmp));
+
+	return 0;
 }
 
 #endif /* CONFIG_IEEE80211R */
@@ -975,6 +1084,39 @@
 #endif /* CONFIG_SUITEB */
 
 
+#ifdef CONFIG_SUITEB192
+/**
+ * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+			  const u8 *spa, u8 *pmkid)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA384_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+	if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
+		return -1;
+	os_memcpy(pmkid, hash, PMKID_LEN);
+	return 0;
+}
+#endif /* CONFIG_SUITEB192 */
+
+
 /**
  * wpa_cipher_txt - Convert cipher suite to a text string
  * @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -1054,6 +1196,8 @@
 		return "OSEN";
 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
 		return "WPA2-EAP-SUITE-B";
+	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+		return "WPA2-EAP-SUITE-B-192";
 	default:
 		return "UNKNOWN";
 	}
@@ -1082,6 +1226,8 @@
 		return WLAN_AKM_SUITE_OSEN;
 	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
 		return WLAN_AKM_SUITE_8021X_SUITE_B;
+	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		return WLAN_AKM_SUITE_8021X_SUITE_B_192;
 	return 0;
 }
 
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 17bed34..29c3503 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
 /*
  * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,8 +9,6 @@
 #ifndef WPA_COMMON_H
 #define WPA_COMMON_H
 
-#define WPA_MAX_SSID_LEN 32
-
 /* IEEE 802.11i */
 #define PMKID_LEN 16
 #define PMK_LEN 32
@@ -63,8 +61,8 @@
 #define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
 #define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
 #define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
-#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 #define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
 #define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
@@ -191,22 +189,38 @@
 	/* followed by key_data_length bytes of key_data */
 } STRUCT_PACKED;
 
+struct wpa_eapol_key_192 {
+	u8 type;
+	/* Note: key_info, key_length, and key_data_length are unaligned */
+	u8 key_info[2]; /* big endian */
+	u8 key_length[2]; /* big endian */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	u8 key_nonce[WPA_NONCE_LEN];
+	u8 key_iv[16];
+	u8 key_rsc[WPA_KEY_RSC_LEN];
+	u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+	u8 key_mic[24];
+	u8 key_data_length[2]; /* big endian */
+	/* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
+#define WPA_KCK_MAX_LEN 24
+#define WPA_KEK_MAX_LEN 32
+#define WPA_TK_MAX_LEN 32
+
 /**
  * struct wpa_ptk - WPA Pairwise Transient Key
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  */
 struct wpa_ptk {
-	u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
-	u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
-	u8 tk1[16]; /* Temporal Key 1 (TK1) */
-	union {
-		u8 tk2[16]; /* Temporal Key 2 (TK2) */
-		struct {
-			u8 tx_mic_key[8];
-			u8 rx_mic_key[8];
-		} auth;
-	} u;
-} STRUCT_PACKED;
+	u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
+	u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
+	u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+	size_t kck_len;
+	size_t kek_len;
+	size_t tk_len;
+};
 
 
 /* WPA IE version 1
@@ -292,7 +306,6 @@
 } STRUCT_PACKED;
 #endif /* CONFIG_IEEE80211W */
 
-#ifdef CONFIG_IEEE80211R
 struct rsn_mdie {
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
 	u8 ft_capab;
@@ -320,23 +333,23 @@
 	le16 status_code;
 } STRUCT_PACKED;
 
-#endif /* CONFIG_IEEE80211R */
 
 #ifdef _MSC_VER
 #pragma pack(pop)
 #endif /* _MSC_VER */
 
 
-int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
-		      size_t len, u8 *mic);
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
-		    const u8 *addr1, const u8 *addr2,
-		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len, int use_sha256);
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+		      const u8 *buf, size_t len, u8 *mic);
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		   const u8 *addr1, const u8 *addr2,
+		   const u8 *nonce1, const u8 *nonce2,
+		   struct wpa_ptk *ptk, int akmp, int cipher);
 
 #ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
-	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+	       const u8 *ap_addr, u8 transaction_seqnum,
+	       const u8 *mdie, size_t mdie_len,
 	       const u8 *ftie, size_t ftie_len,
 	       const u8 *rsnie, size_t rsnie_len,
 	       const u8 *ric, size_t ric_len, u8 *mic);
@@ -349,10 +362,10 @@
 void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
 		       const u8 *r1kh_id, const u8 *s1kh_id,
 		       u8 *pmk_r1, u8 *pmk_r1_name);
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
-		       const u8 *sta_addr, const u8 *bssid,
-		       const u8 *pmk_r1_name,
-		       u8 *ptk, size_t ptk_len, u8 *ptk_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		      const u8 *sta_addr, const u8 *bssid,
+		      const u8 *pmk_r1_name,
+		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
 #endif /* CONFIG_IEEE80211R */
 
 struct wpa_ie_data {
@@ -384,6 +397,16 @@
 	return -1;
 }
 #endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+			  const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB192 */
+static inline int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len,
+					const u8 *aa, const u8 *spa, u8 *pmkid)
+{
+	return -1;
+}
+#endif /* CONFIG_SUITEB192 */
 
 const char * wpa_cipher_txt(int cipher);
 const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
@@ -429,5 +452,6 @@
 int wpa_parse_cipher(const char *value);
 int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
 int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+unsigned int wpa_mic_len(int akmp);
 
 #endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index ccaaf1b..82d4655 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
 
 #ifdef ANDROID
 #include <dirent.h>
+#include <sys/stat.h>
 #include <cutils/sockets.h>
 #include "private/android_filesystem_config.h"
 #endif /* ANDROID */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 1f747eb..e3a816f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -42,6 +42,8 @@
 #define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
 /** EAP peer certificate from TLS */
 #define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP peer certificate alternative subject name component from TLS */
+#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
 /** EAP TLS certificate chain validation error */
 #define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
 /** EAP status */
@@ -125,6 +127,9 @@
 #define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
 #define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
 #define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+/** Mesh SAE authentication failure. Wrong password suspected. */
+#define MESH_SAE_AUTH_FAILURE "MESH-SAE-AUTH-FAILURE "
+#define MESH_SAE_AUTH_BLOCKED "MESH-SAE-AUTH-BLOCKED "
 
 /* WMM AC events */
 #define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
@@ -162,6 +167,7 @@
 #define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
 /* parameters: <src addr> <update indicator> <TLVs> */
 #define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
+#define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP "
 #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
@@ -170,11 +176,16 @@
 #define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO "
 #define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT "
 #define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG "P2P-FALLBACK-TO-GO-NEG "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED "P2P-FALLBACK-TO-GO-NEG-ENABLED "
 
 /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
 #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
 #define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
 
+#define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START "
+#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
+
 #define INTERWORKING_AP "INTERWORKING-AP "
 #define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
 #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
@@ -194,6 +205,9 @@
 /* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
 #define GAS_QUERY_DONE "GAS-QUERY-DONE "
 
+/* parameters: <addr> <result> */
+#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+
 #define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
 #define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
 
@@ -213,6 +227,7 @@
 #define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
 #define AP_STA_CONNECTED "AP-STA-CONNECTED "
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
 
 #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
 #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@@ -260,6 +275,8 @@
 #define WPA_BSS_MASK_WIFI_DISPLAY	BIT(16)
 #define WPA_BSS_MASK_DELIM		BIT(17)
 #define WPA_BSS_MASK_MESH_SCAN		BIT(18)
+#define WPA_BSS_MASK_SNR		BIT(19)
+#define WPA_BSS_MASK_EST_THROUGHPUT	BIT(20)
 
 
 /* VENDOR_ELEM_* frame id values */
@@ -277,6 +294,7 @@
 	VENDOR_ELEM_P2P_INV_RESP = 10,
 	VENDOR_ELEM_P2P_ASSOC_REQ = 11,
 	VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+	VENDOR_ELEM_ASSOC_REQ = 13,
 	NUM_VENDOR_ELEM_FRAMES
 };
 
diff --git a/src/crypto/aes-eax.c b/src/crypto/aes-eax.c
index 21941c6..15a09f8 100644
--- a/src/crypto/aes-eax.c
+++ b/src/crypto/aes-eax.c
@@ -71,7 +71,7 @@
 
 	ret = 0;
 fail:
-	os_free(buf);
+	bin_clear_free(buf, buf_len);
 
 	return ret;
 }
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index c2b0686..375db57 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -1,5 +1,5 @@
 /*
- * One-key CBC MAC (OMAC1) hash with AES-128
+ * One-key CBC MAC (OMAC1) hash with AES
  *
  * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
  *
@@ -27,8 +27,9 @@
 
 
 /**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
  * @num_elem: Number of elements in the data vector
  * @addr: Pointers to the data areas
  * @len: Lengths of the data blocks
@@ -39,15 +40,15 @@
  * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
  * (SP) 800-38B.
  */
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
-			 const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
 {
 	void *ctx;
 	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
 	const u8 *pos, *end;
 	size_t i, e, left, total_len;
 
-	ctx = aes_encrypt_init(key, 16);
+	ctx = aes_encrypt_init(key, key_len);
 	if (ctx == NULL)
 		return -1;
 	os_memset(cbc, 0, AES_BLOCK_SIZE);
@@ -114,6 +115,26 @@
 
 
 /**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
  * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
  * @key: 128-bit key for the hash operation
  * @data: Data buffer for which a MAC is determined
@@ -129,3 +150,21 @@
 {
 	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
 }
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
index ff4b823..5ac82c2 100644
--- a/src/crypto/aes-siv.c
+++ b/src/crypto/aes-siv.c
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "aes.h"
 #include "aes_wrap.h"
+#include "aes_siv.h"
 
 
 static const u8 zero[AES_BLOCK_SIZE];
@@ -60,8 +61,8 @@
 }
 
 
-int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
-	    size_t *len, u8 *mac)
+static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+		   size_t *len, u8 *mac)
 {
 	u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
 	u8 *buf = NULL;
@@ -94,7 +95,7 @@
 		os_memcpy(buf, addr[i], len[i]);
 		xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
 		ret = omac1_aes_128(key, buf, len[i], mac);
-		os_free(buf);
+		bin_clear_free(buf, len[i]);
 		return ret;
 	}
 
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 6b3727c..4a14209 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -2,7 +2,7 @@
  * AES-based functions
  *
  * - AES Key Wrap Algorithm (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
  * - AES-128 CTR mode encryption
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
@@ -22,11 +22,16 @@
 			  u8 *cipher);
 int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
 			    const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_vector(const u8 *key, size_t key_len,
+				  size_t num_elem, const u8 *addr[],
+				  const size_t *len, u8 *mac);
 int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
 				      const u8 *addr[], const size_t *len,
 				      u8 *mac);
 int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
 			       u8 *mac);
+int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
+			       u8 *mac);
 int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
 int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
 				     u8 *data, size_t data_len);
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
deleted file mode 100644
index 55a069b..0000000
--- a/src/crypto/crypto_cryptoapi.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-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 <windows.h>
-#include <wincrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef MS_ENH_RSA_AES_PROV
-#ifdef UNICODE
-#define MS_ENH_RSA_AES_PROV \
-L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#else
-#define MS_ENH_RSA_AES_PROV \
-"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#endif
-#endif /* MS_ENH_RSA_AES_PROV */
-
-#ifndef CALG_HMAC
-#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
-#endif
-
-#ifdef __MINGW32_VERSION
-/*
- * MinGW does not yet include all the needed definitions for CryptoAPI, so
- * define here whatever extra is needed.
- */
-
-static BOOL WINAPI
-(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
-			    PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
-= NULL; /* to be loaded from crypt32.dll */
-
-
-static int mingw_load_crypto_func(void)
-{
-	HINSTANCE dll;
-
-	/* MinGW does not yet have full CryptoAPI support, so load the needed
-	 * function here. */
-
-	if (CryptImportPublicKeyInfo)
-		return 0;
-
-	dll = LoadLibrary("crypt32");
-	if (dll == NULL) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
-			   "library");
-		return -1;
-	}
-
-	CryptImportPublicKeyInfo = GetProcAddress(
-		dll, "CryptImportPublicKeyInfo");
-	if (CryptImportPublicKeyInfo == NULL) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
-			   "CryptImportPublicKeyInfo() address from "
-			   "crypt32 library");
-		return -1;
-	}
-
-	return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
-	return 0;
-}
-
-#endif /* __MINGW32_VERSION */
-
-
-static void cryptoapi_report_error(const char *msg)
-{
-	char *s, *pos;
-	DWORD err = GetLastError();
-
-	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-			  FORMAT_MESSAGE_FROM_SYSTEM,
-			  NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
-	}
-
-	pos = s;
-	while (*pos) {
-		if (*pos == '\n' || *pos == '\r') {
-			*pos = '\0';
-			break;
-		}
-		pos++;
-	}
-
-	wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
-	LocalFree(s);
-}
-
-
-int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
-			  const u8 *addr[], const size_t *len, u8 *mac)
-{
-	HCRYPTPROV prov;
-	HCRYPTHASH hash;
-	size_t i;
-	DWORD hlen;
-	int ret = 0;
-
-	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		return -1;
-	}
-
-	if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
-		cryptoapi_report_error("CryptCreateHash");
-		CryptReleaseContext(prov, 0);
-		return -1;
-	}
-
-	for (i = 0; i < num_elem; i++) {
-		if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
-			cryptoapi_report_error("CryptHashData");
-			CryptDestroyHash(hash);
-			CryptReleaseContext(prov, 0);
-		}
-	}
-
-	hlen = hash_len;
-	if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
-		cryptoapi_report_error("CryptGetHashParam");
-		ret = -1;
-	}
-
-	CryptDestroyHash(hash);
-	CryptReleaseContext(prov, 0);
-
-	return ret;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	u8 next, tmp;
-	int i;
-	HCRYPTPROV prov;
-	HCRYPTKEY ckey;
-	DWORD dlen;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[8];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_ECB;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.hdr.aiKeyAlg = CALG_DES;
-	key_blob.len = 8;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		key_blob.key[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	key_blob.key[i] = next | 1;
-
-	if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
-				 CRYPT_VERIFYCONTEXT)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
-			   "%d", (int) GetLastError());
-		return;
-	}
-
-	if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
-			    &ckey)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
-			   (int) GetLastError());
-		CryptReleaseContext(prov, 0);
-		return;
-	}
-
-	if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
-			   "failed: %d", (int) GetLastError());
-		CryptDestroyKey(ckey);
-		CryptReleaseContext(prov, 0);
-		return;
-	}
-
-	os_memcpy(cypher, clear, 8);
-	dlen = 8;
-	if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
-			   (int) GetLastError());
-		os_memset(cypher, 0, 8);
-	}
-
-	CryptDestroyKey(ckey);
-	CryptReleaseContext(prov, 0);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
-}
-
-
-struct aes_context {
-	HCRYPTPROV prov;
-	HCRYPTKEY ckey;
-};
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	struct aes_context *akey;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[16];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_ECB;
-
-	if (len != 16)
-		return NULL;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.hdr.aiKeyAlg = CALG_AES_128;
-	key_blob.len = len;
-	os_memcpy(key_blob.key, key, len);
-
-	akey = os_zalloc(sizeof(*akey));
-	if (akey == NULL)
-		return NULL;
-
-	if (!CryptAcquireContext(&akey->prov, NULL,
-				 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
-				 CRYPT_VERIFYCONTEXT)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
-			   "%d", (int) GetLastError());
-		os_free(akey);
-		return NULL;
-	}
-
-	if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
-			    0, 0, &akey->ckey)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
-			   (int) GetLastError());
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-		return NULL;
-	}
-
-	if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
-			   "failed: %d", (int) GetLastError());
-		CryptDestroyKey(akey->ckey);
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-		return NULL;
-	}
-
-	return akey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	struct aes_context *akey = ctx;
-	DWORD dlen;
-
-	os_memcpy(crypt, plain, 16);
-	dlen = 16;
-	if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
-			   (int) GetLastError());
-		os_memset(crypt, 0, 16);
-	}
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	struct aes_context *akey = ctx;
-	if (akey) {
-		CryptDestroyKey(akey->ckey);
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-	}
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	return aes_encrypt_init(key, len);
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	struct aes_context *akey = ctx;
-	DWORD dlen;
-
-	os_memcpy(plain, crypt, 16);
-	dlen = 16;
-
-	if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
-			   (int) GetLastError());
-	}
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	aes_encrypt_deinit(ctx);
-}
-
-
-struct crypto_hash {
-	enum crypto_hash_alg alg;
-	int error;
-	HCRYPTPROV prov;
-	HCRYPTHASH hash;
-	HCRYPTKEY key;
-};
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
-				      size_t key_len)
-{
-	struct crypto_hash *ctx;
-	ALG_ID calg;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[32];
-	} key_blob;
-
-	os_memset(&key_blob, 0, sizeof(key_blob));
-	switch (alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		calg = CALG_MD5;
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		calg = CALG_SHA;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		calg = CALG_HMAC;
-		key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-		key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-		key_blob.hdr.reserved = 0;
-		/*
-		 * Note: RC2 is not really used, but that can be used to
-		 * import HMAC keys of up to 16 byte long.
-		 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
-		 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
-		 */
-		key_blob.hdr.aiKeyAlg = CALG_RC2;
-		key_blob.len = key_len;
-		if (key_len > sizeof(key_blob.key))
-			return NULL;
-		os_memcpy(key_blob.key, key, key_len);
-		break;
-	default:
-		return NULL;
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	ctx->alg = alg;
-
-	if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (calg == CALG_HMAC) {
-#ifndef CRYPT_IPSEC_HMAC_KEY
-#define CRYPT_IPSEC_HMAC_KEY 0x00000100
-#endif
-		if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
-				    sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
-				    &ctx->key)) {
-			cryptoapi_report_error("CryptImportKey");
-			CryptReleaseContext(ctx->prov, 0);
-			os_free(ctx);
-			return NULL;
-		}
-	}
-
-	if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
-		cryptoapi_report_error("CryptCreateHash");
-		CryptReleaseContext(ctx->prov, 0);
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (calg == CALG_HMAC) {
-		HMAC_INFO info;
-		os_memset(&info, 0, sizeof(info));
-		switch (alg) {
-		case CRYPTO_HASH_ALG_HMAC_MD5:
-			info.HashAlgid = CALG_MD5;
-			break;
-		case CRYPTO_HASH_ALG_HMAC_SHA1:
-			info.HashAlgid = CALG_SHA;
-			break;
-		default:
-			/* unreachable */
-			break;
-		}
-
-		if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
-				       0)) {
-			cryptoapi_report_error("CryptSetHashParam");
-			CryptDestroyHash(ctx->hash);
-			CryptReleaseContext(ctx->prov, 0);
-			os_free(ctx);
-			return NULL;
-		}
-	}
-
-	return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
-	if (ctx == NULL || ctx->error)
-		return;
-
-	if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
-		cryptoapi_report_error("CryptHashData");
-		ctx->error = 1;
-	}
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
-	int ret = 0;
-	DWORD hlen;
-
-	if (ctx == NULL)
-		return -2;
-
-	if (mac == NULL || len == NULL)
-		goto done;
-
-	if (ctx->error) {
-		ret = -2;
-		goto done;
-	}
-
-	hlen = *len;
-	if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
-		cryptoapi_report_error("CryptGetHashParam");
-		ret = -2;
-	}
-	*len = hlen;
-
-done:
-	if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
-	    ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
-		CryptDestroyKey(ctx->key);
-
-	os_free(ctx);
-
-	return ret;
-}
-
-
-struct crypto_cipher {
-	HCRYPTPROV prov;
-	HCRYPTKEY key;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{	
-	struct crypto_cipher *ctx;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[32];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_CBC;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.len = key_len;
-	if (key_len > sizeof(key_blob.key))
-		return NULL;
-	os_memcpy(key_blob.key, key, key_len);
-
-	switch (alg) {
-	case CRYPTO_CIPHER_ALG_AES:
-		if (key_len == 32)
-			key_blob.hdr.aiKeyAlg = CALG_AES_256;
-		else if (key_len == 24)
-			key_blob.hdr.aiKeyAlg = CALG_AES_192;
-		else
-			key_blob.hdr.aiKeyAlg = CALG_AES_128;
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		key_blob.hdr.aiKeyAlg = CALG_3DES;
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		key_blob.hdr.aiKeyAlg = CALG_DES;
-		break;
-	case CRYPTO_CIPHER_ALG_RC2:
-		key_blob.hdr.aiKeyAlg = CALG_RC2;
-		break;
-	case CRYPTO_CIPHER_ALG_RC4:
-		key_blob.hdr.aiKeyAlg = CALG_RC4;
-		break;
-	default:
-		return NULL;
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
-				 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		goto fail1;
-	}
-
-	if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
-			    sizeof(key_blob), 0, 0, &ctx->key)) {
- 		cryptoapi_report_error("CryptImportKey");
-		goto fail2;
-	}
-
-	if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
- 		cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
-		goto fail3;
-	}
-
-	if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
- 		cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
-		goto fail3;
-	}
-
-	return ctx;
-
-fail3:
-	CryptDestroyKey(ctx->key);
-fail2:
-	CryptReleaseContext(ctx->prov, 0);
-fail1:
-	os_free(ctx);
-	return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	DWORD dlen;
-
-	os_memcpy(crypt, plain, len);
-	dlen = len;
-	if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
- 		cryptoapi_report_error("CryptEncrypt");
-		os_memset(crypt, 0, len);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	DWORD dlen;
-
-	os_memcpy(plain, crypt, len);
-	dlen = len;
-	if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
- 		cryptoapi_report_error("CryptDecrypt");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-	CryptDestroyKey(ctx->key);
-	CryptReleaseContext(ctx->prov, 0);
-	os_free(ctx);
-}
-
-
-struct crypto_public_key {
-	HCRYPTPROV prov;
-	HCRYPTKEY rsa;
-};
-
-struct crypto_private_key {
-	HCRYPTPROV prov;
-	HCRYPTKEY rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
-	/* Use crypto_public_key_from_cert() instead. */
-	return NULL;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
-						      size_t len,
-						      const char *passwd)
-{
-	/* TODO */
-	return NULL;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
-						       size_t len)
-{
-	struct crypto_public_key *pk;
-	PCCERT_CONTEXT cc;
-
-	pk = os_zalloc(sizeof(*pk));
-	if (pk == NULL)
-		return NULL;
-
-	cc = CertCreateCertificateContext(X509_ASN_ENCODING |
-					  PKCS_7_ASN_ENCODING, buf, len);
-	if (!cc) {
- 		cryptoapi_report_error("CryptCreateCertificateContext");
-		os_free(pk);
-		return NULL;
-	}
-
-	if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
-				 0)) {
- 		cryptoapi_report_error("CryptAcquireContext");
-		os_free(pk);
-		CertFreeCertificateContext(cc);
-		return NULL;
-	}
-
-	if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
-				      PKCS_7_ASN_ENCODING,
-				      &cc->pCertInfo->SubjectPublicKeyInfo,
-				      &pk->rsa)) {
- 		cryptoapi_report_error("CryptImportPublicKeyInfo");
-		CryptReleaseContext(pk->prov, 0);
-		os_free(pk);
-		CertFreeCertificateContext(cc);
-		return NULL;
-	}
-
-	CertFreeCertificateContext(cc);
-
-	return pk;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
-					const u8 *in, size_t inlen,
-					u8 *out, size_t *outlen)
-{
-	DWORD clen;
-	u8 *tmp;
-	size_t i;
-
-	if (*outlen < inlen)
-		return -1;
-	tmp = malloc(*outlen);
-	if (tmp == NULL)
-		return -1;
-
-	os_memcpy(tmp, in, inlen);
-	clen = inlen;
-	if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
-			   "public key: %d", (int) GetLastError());
-		os_free(tmp);
-		return -1;
-	}
-
-	*outlen = clen;
-
-	/* Reverse the output */
-	for (i = 0; i < *outlen; i++)
-		out[i] = tmp[*outlen - 1 - i];
-
-	os_free(tmp);
-
-	return 0;
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen)
-{
-	/* TODO */
-	return -1;
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
-	if (key) {
-		CryptDestroyKey(key->rsa);
-		CryptReleaseContext(key->prov, 0);
-		os_free(key);
-	}
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
-	if (key) {
-		CryptDestroyKey(key->rsa);
-		CryptReleaseContext(key->prov, 0);
-		os_free(key);
-	}
-}
-
-
-int crypto_global_init(void)
-{
-	return mingw_load_crypto_func();
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	/* TODO */
-	return -1;
-}
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
new file mode 100644
index 0000000..7137c27
--- /dev/null
+++ b/src/crypto/crypto_module_tests.c
@@ -0,0 +1,1679 @@
+/*
+ * crypto module tests
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "crypto/aes_siv.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/aes.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+
+
+static int test_siv(void)
+{
+#ifdef CONFIG_MESH
+	/* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+	u8 key[] = {
+		0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+		0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+		0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+		0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+	};
+	u8 ad[] = {
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+		0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+	};
+	u8 plaintext[] = {
+		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+		0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+	};
+	u8 iv_c[] = {
+		0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+		0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+		0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+		0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+	};
+	/* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+	u8 key_2[] = {
+		0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+		0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+		0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+		0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+	};
+	u8 ad1_2[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+		0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda,
+		0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+		0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00
+	};
+	u8 ad2_2[] = {
+		0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+		0x90, 0xa0
+	};
+	u8 nonce_2[] = {
+		0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+		0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+	};
+	u8 plaintext_2[] = {
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+		0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61,
+		0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74,
+		0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+		0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20,
+		0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53
+	};
+	u8 iv_c_2[] = {
+		0x7b, 0xdb, 0x6e, 0x3b, 0x43, 0x26, 0x67, 0xeb,
+		0x06, 0xf4, 0xd1, 0x4b, 0xff, 0x2f, 0xbd, 0x0f,
+		0xcb, 0x90, 0x0f, 0x2f, 0xdd, 0xbe, 0x40, 0x43,
+		0x26, 0x60, 0x19, 0x65, 0xc8, 0x89, 0xbf, 0x17,
+		0xdb, 0xa7, 0x7c, 0xeb, 0x09, 0x4f, 0xa6, 0x63,
+		0xb7, 0xa3, 0xf7, 0x48, 0xba, 0x8a, 0xf8, 0x29,
+		0xea, 0x64, 0xad, 0x54, 0x4a, 0x27, 0x2e, 0x9c,
+		0x48, 0x5b, 0x62, 0xa3, 0xfd, 0x5c, 0x0d
+	};
+	u8 out[2 * AES_BLOCK_SIZE + sizeof(plaintext_2)];
+	const u8 *addr[3];
+	size_t len[3];
+
+	/* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+	addr[0] = ad;
+	len[0] = sizeof(ad);
+
+	if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+			    1, addr, len, out)) {
+		wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+		return 1;
+	}
+	if (os_memcmp(out, iv_c, sizeof(iv_c)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-SIV mode encryption returned invalid cipher text");
+		return 1;
+	}
+
+	if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+		wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+		return 1;
+	}
+	if (os_memcmp(out, plaintext, sizeof(plaintext)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-SIV mode decryption returned invalid plain text");
+		return 1;
+	}
+
+	/* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+	addr[0] = ad1_2;
+	len[0] = sizeof(ad1_2);
+	addr[1] = ad2_2;
+	len[1] = sizeof(ad2_2);
+	addr[2] = nonce_2;
+	len[2] = sizeof(nonce_2);
+
+	if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+			    3, addr, len, out)) {
+		wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+		return 1;
+	}
+	if (os_memcmp(out, iv_c_2, sizeof(iv_c_2)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-SIV mode encryption returned invalid cipher text");
+		return 1;
+	}
+
+	if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+		wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+		return 1;
+	}
+	if (os_memcmp(out, plaintext_2, sizeof(plaintext_2)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-SIV mode decryption returned invalid plain text");
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "AES-SIV test cases passed");
+#endif /* CONFIG_MESH */
+
+	return 0;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ * which are same as the examples from NIST SP800-38B
+ * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ */
+
+struct omac1_test_vector {
+	u8 k[16];
+	u8 msg[64];
+	int msg_len;
+	u8 tag[16];
+};
+
+static struct omac1_test_vector omac1_test_vectors[] =
+{
+	{
+		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+		{ },
+		0,
+		{ 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+		  0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+	},
+	{
+		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+		16,
+		{ 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+		  0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+	},
+	{
+		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+		40,
+		{ 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+		  0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+	},
+	{
+		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+		  0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+		  0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+		  0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+		64,
+		{ 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+		  0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+	},
+};
+
+
+static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+{
+	u8 key[] = {
+		0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+	};
+	u8 msg[] = { 0x12, 0x34, 0x56 };
+	u8 result[24], result2[24];
+	const u8 *addr[3];
+	size_t len[3];
+
+	if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
+	    os_memcmp(result, tv->tag, 16) != 0) {
+		wpa_printf(MSG_ERROR, "OMAC1-AES-128 test vector %u failed", i);
+		return 1;
+	}
+
+	if (tv->msg_len > 1) {
+
+		addr[0] = tv->msg;
+		len[0] = 1;
+		addr[1] = tv->msg + 1;
+		len[1] = tv->msg_len - 1;
+
+		if (omac1_aes_128_vector(tv->k, 2, addr, len, result) ||
+		    os_memcmp(result, tv->tag, 16) != 0) {
+			wpa_printf(MSG_ERROR,
+				   "OMAC1-AES-128(vector) test vector %u failed",
+				   i);
+			return 1;
+		}
+
+		addr[0] = tv->msg;
+		len[0] = tv->msg_len - 2;
+		addr[1] = tv->msg + tv->msg_len - 2;
+		len[1] = 1;
+		addr[2] = tv->msg + tv->msg_len - 1;
+		len[2] = 1;
+
+		if (omac1_aes_128_vector(tv->k, 3, addr, len, result) ||
+		    os_memcmp(result, tv->tag, 16) != 0) {
+			wpa_printf(MSG_ERROR,
+				   "OMAC1-AES-128(vector2) test vector %u failed",
+				   i);
+			return 1;
+		}
+	}
+
+	addr[0] = &msg[0];
+	len[0] = 1;
+	addr[1] = &msg[1];
+	len[1] = 1;
+	addr[2] = &msg[2];
+	len[2] = 1;
+	if (omac1_aes_128(key, msg, sizeof(msg), result) ||
+	    omac1_aes_128_vector(key, 3, addr, len, result2) ||
+	    os_memcmp(result, result2, 16) != 0) {
+		wpa_printf(MSG_ERROR, "OMAC1-AES-128 short test mismatch");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int test_omac1(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(omac1_test_vectors); i++) {
+		if (test_omac1_vector(&omac1_test_vectors[i], i))
+			return 1;
+	}
+
+	wpa_printf(MSG_INFO, "OMAC1-AES-128 test cases passed");
+
+	return 0;
+}
+
+
+static int test_eax(void)
+{
+#ifdef EAP_PSK
+	u8 msg[] = { 0xF7, 0xFB };
+	u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+		     0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+	u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+		       0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+	u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+	u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+			0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+			0x67, 0xE5 };
+	u8 data[sizeof(msg)], tag[AES_BLOCK_SIZE];
+
+	os_memcpy(data, msg, sizeof(msg));
+	if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+				data, sizeof(data), tag)) {
+		wpa_printf(MSG_ERROR, "AES-128 EAX mode encryption failed");
+		return 1;
+	}
+	if (os_memcmp(data, cipher, sizeof(data)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-128 EAX mode encryption returned invalid cipher text");
+		return 1;
+	}
+	if (os_memcmp(tag, cipher + sizeof(data), AES_BLOCK_SIZE) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-128 EAX mode encryption returned invalid tag");
+		return 1;
+	}
+
+	if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+				data, sizeof(data), tag)) {
+		wpa_printf(MSG_ERROR, "AES-128 EAX mode decryption failed");
+		return 1;
+	}
+	if (os_memcmp(data, msg, sizeof(data)) != 0) {
+		wpa_printf(MSG_ERROR,
+			   "AES-128 EAX mode decryption returned invalid plain text");
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "AES-128 EAX mode test cases passed");
+#endif /* EAP_PSK */
+
+	return 0;
+}
+
+
+static int test_cbc(void)
+{
+	struct cbc_test_vector {
+		u8 key[16];
+		u8 iv[16];
+		u8 plain[32];
+		u8 cipher[32];
+		size_t len;
+	} vectors[] = {
+		{
+			{ 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+			  0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+			{ 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+			  0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+			"Single block msg",
+			{ 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+			  0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+			16
+		},
+		{
+			{ 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+			  0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+			{ 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+			  0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+			{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+			  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+			  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+			{ 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+			  0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+			  0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+			  0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+			32
+		}
+	};
+	int ret = 0;
+	u8 *buf;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+		struct cbc_test_vector *tv = &vectors[i];
+
+		buf = os_malloc(tv->len);
+		if (buf == NULL) {
+			ret++;
+			break;
+		}
+
+		os_memcpy(buf, tv->plain, tv->len);
+		if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
+		    os_memcmp(buf, tv->cipher, tv->len) != 0) {
+			wpa_printf(MSG_ERROR, "AES-CBC encrypt %d failed", i);
+			ret++;
+		}
+
+		os_memcpy(buf, tv->cipher, tv->len);
+		if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
+		    os_memcmp(buf, tv->plain, tv->len) != 0) {
+			wpa_printf(MSG_ERROR, "AES-CBC decrypt %d failed", i);
+			ret++;
+		}
+
+		os_free(buf);
+	}
+
+	return ret;
+}
+
+
+static int test_ecb(void)
+{
+#ifdef EAP_PSK
+	struct ecb_test_vector {
+		char *key;
+		char *plaintext;
+		char *ciphertext;
+	} vectors[] = {
+		/* CAVS 11.1 - ECBGFSbox128.rsp */
+		{
+			"00000000000000000000000000000000",
+			"f34481ec3cc627bacd5dc3fb08f273e6",
+			"0336763e966d92595a567cc9ce537f5e"
+		},
+		{
+			"00000000000000000000000000000000",
+			"9798c4640bad75c7c3227db910174e72",
+			"a9a1631bf4996954ebc093957b234589"
+		},
+		{
+			"00000000000000000000000000000000",
+			"96ab5c2ff612d9dfaae8c31f30c42168",
+			"ff4f8391a6a40ca5b25d23bedd44a597"
+		},
+		{
+			"00000000000000000000000000000000",
+			"6a118a874519e64e9963798a503f1d35",
+			"dc43be40be0e53712f7e2bf5ca707209"
+		},
+		{
+			"00000000000000000000000000000000",
+			"cb9fceec81286ca3e989bd979b0cb284",
+			"92beedab1895a94faa69b632e5cc47ce"
+		},
+		{
+			"00000000000000000000000000000000",
+			"b26aeb1874e47ca8358ff22378f09144",
+			"459264f4798f6a78bacb89c15ed3d601"
+		},
+		{
+			"00000000000000000000000000000000",
+			"58c8e00b2631686d54eab84b91f0aca1",
+			"08a4e2efec8a8e3312ca7460b9040bbf"
+		},
+		/* CAVS 11.1 - ECBKeySbox128.rsp */
+		{
+			"10a58869d74be5a374cf867cfb473859",
+			"00000000000000000000000000000000",
+			"6d251e6944b051e04eaa6fb4dbf78465"
+		},
+		{
+			"caea65cdbb75e9169ecd22ebe6e54675",
+			"00000000000000000000000000000000",
+			"6e29201190152df4ee058139def610bb",
+		}
+	};
+	int ret = 0;
+	unsigned int i;
+	u8 key[16], plain[16], cipher[16], out[16];
+
+	for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+		struct ecb_test_vector *tv = &vectors[i];
+
+		if (hexstr2bin(tv->key, key, sizeof(key)) ||
+		    hexstr2bin(tv->plaintext, plain, sizeof(plain)) ||
+		    hexstr2bin(tv->ciphertext, cipher, sizeof(cipher))) {
+			wpa_printf(MSG_ERROR, "Invalid AES-ECB test vector %u",
+				   i);
+			ret++;
+			continue;
+		}
+
+		if (aes_128_encrypt_block(key, plain, out) < 0 ||
+		    os_memcmp(out, cipher, 16) != 0) {
+			wpa_printf(MSG_ERROR, "AES-ECB encrypt %u failed", i);
+			ret++;
+		}
+	}
+
+	if (!ret)
+		wpa_printf(MSG_INFO, "AES ECB mode test cases passed");
+
+	return ret;
+#endif /* EAP_PSK */
+
+	return 0;
+}
+
+
+static int test_key_wrap(void)
+{
+	int ret = 0;
+
+	/* RFC 3394 - Test vector 4.1 */
+	u8 kek41[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+	};
+	u8 plain41[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+	};
+	u8 crypt41[] = {
+		0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+		0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+		0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+	};
+	/* RFC 3394 - Test vector 4.2 */
+	u8 kek42[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+	};
+	u8 plain42[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+	};
+	u8 crypt42[] = {
+		0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
+		0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
+		0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
+	};
+	/* RFC 3394 - Test vector 4.3 */
+	u8 kek43[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+	};
+	u8 plain43[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+	};
+	u8 crypt43[] = {
+		0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
+		0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
+		0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
+	};
+	/* RFC 3394 - Test vector 4.4 */
+	u8 kek44[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+	};
+	u8 plain44[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+	};
+	u8 crypt44[] = {
+		0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
+		0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
+		0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
+		0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
+	};
+	/* RFC 3394 - Test vector 4.5 */
+	u8 kek45[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+	};
+	u8 plain45[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+	};
+	u8 crypt45[] = {
+		0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
+		0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
+		0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
+		0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,
+	};
+	/* RFC 3394 - Test vector 4.6 */
+	u8 kek46[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+	};
+	u8 plain46[] = {
+		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+	};
+	u8 crypt46[] = {
+		0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
+		0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
+		0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
+		0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
+		0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21
+	};
+	u8 result[40];
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.1");
+	if (aes_wrap(kek41, sizeof(kek41), sizeof(plain41) / 8, plain41,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-128 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt41, sizeof(crypt41)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-128 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek41, sizeof(kek41), sizeof(plain41) / 8, crypt41,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-128 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain41, sizeof(plain41)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-128 failed");
+		ret++;
+	}
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
+	if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt42, sizeof(crypt42)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek42, sizeof(kek42), sizeof(plain42) / 8, crypt42,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain42, sizeof(plain42)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+		ret++;
+	}
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
+	if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt43, sizeof(crypt43)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek43, sizeof(kek43), sizeof(plain43) / 8, crypt43,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain43, sizeof(plain43)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+		ret++;
+	}
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
+	if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt44, sizeof(crypt44)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek44, sizeof(kek44), sizeof(plain44) / 8, crypt44,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain44, sizeof(plain44)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+		ret++;
+	}
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
+	if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt45, sizeof(crypt45)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek45, sizeof(kek45), sizeof(plain45) / 8, crypt45,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain45, sizeof(plain45)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+		ret++;
+	}
+
+	wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.6");
+	if (aes_wrap(kek46, sizeof(kek46), sizeof(plain46) / 8, plain46,
+		     result)) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, crypt46, sizeof(crypt46)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+		ret++;
+	}
+	if (aes_unwrap(kek46, sizeof(kek46), sizeof(plain46) / 8, crypt46,
+		       result)) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+		ret++;
+	}
+	if (os_memcmp(result, plain46, sizeof(plain46)) != 0) {
+		wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+		ret++;
+	}
+
+	if (!ret)
+		wpa_printf(MSG_INFO, "AES key wrap/unwrap test cases passed");
+
+	return ret;
+}
+
+
+static int test_md5(void)
+{
+	struct {
+		char *data;
+		char *hash;
+	} tests[] = {
+		{
+			"",
+			"\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+			"\xe9\x80\x09\x98\xec\xf8\x42\x7e"
+		},
+		{
+			"a",
+			"\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+			"\x31\xc3\x99\xe2\x69\x77\x26\x61"
+		},
+		{
+			"abc",
+			"\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+			"\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+		},
+		{
+			"message digest",
+			"\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+			"\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
+		},
+		{
+			"abcdefghijklmnopqrstuvwxyz",
+			"\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+			"\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
+		},
+		{
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+			"0123456789",
+			"\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+			"\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
+		},
+		{
+			"12345678901234567890123456789012345678901234567890"
+			"123456789012345678901234567890",
+			"\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+			"\xac\x49\xda\x2e\x21\x07\xb6\x7a"
+		}
+	};
+	unsigned int i;
+	u8 hash[16];
+	const u8 *addr[2];
+	size_t len[2];
+	int errors = 0;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		wpa_printf(MSG_INFO, "MD5 test case %d", i);
+
+		addr[0] = (u8 *) tests[i].data;
+		len[0] = strlen(tests[i].data);
+		if (md5_vector(1, addr, len, hash) < 0 ||
+		    os_memcmp(hash, tests[i].hash, 16) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		if (len[0]) {
+			addr[0] = (u8 *) tests[i].data;
+			len[0] = strlen(tests[i].data);
+			addr[1] = (u8 *) tests[i].data + 1;
+			len[1] = strlen(tests[i].data) - 1;
+			if (md5_vector(1, addr, len, hash) < 0 ||
+			    os_memcmp(hash, tests[i].hash, 16) != 0) {
+				wpa_printf(MSG_INFO, " FAIL");
+				errors++;
+			} else
+				wpa_printf(MSG_INFO, " OK");
+		}
+	}
+
+	if (!errors)
+		wpa_printf(MSG_INFO, "MD5 test cases passed");
+
+	return errors;
+}
+
+
+static int test_eap_fast(void)
+{
+#ifdef EAP_FAST
+	/* RFC 4851, Appendix B.1 */
+	const u8 pac_key[] = {
+		0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
+		0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
+		0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
+		0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
+	};
+	const u8 seed[] = {
+		0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
+		0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
+		0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
+		0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
+		0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
+		0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
+		0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
+		0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
+	};
+	const u8 master_secret[] = {
+		0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
+		0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
+		0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
+		0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
+		0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
+		0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
+	};
+	const u8 key_block[] = {
+		0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
+		0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
+		0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
+		0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
+		0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
+		0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
+		0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
+		0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
+		0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
+		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+	};
+	const u8 sks[] = {
+		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+	};
+	const u8 isk[] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	const u8 imck[] = {
+		0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
+		0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
+		0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
+		0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
+		0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
+		0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
+		0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
+		0x15, 0xEC, 0x57, 0x7B
+	};
+	const u8 msk[] = {
+		0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
+		0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
+		0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
+		0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
+		0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
+		0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
+		0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
+		0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
+	};
+	const u8 emsk[] = {
+		0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
+		0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
+		0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
+		0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
+		0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
+		0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
+		0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
+		0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
+	};
+	/* RFC 4851, Appendix B.2 */
+	u8 tlv[] = {
+		0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
+		0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
+		0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
+		0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
+		0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
+		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+		0x05, 0xC5, 0x5B, 0xB7
+	};
+	const u8 compound_mac[] = {
+		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+		0x05, 0xC5, 0x5B, 0xB7
+	};
+	u8 buf[512];
+	const u8 *simck, *cmk;
+	int errors = 0;
+
+	wpa_printf(MSG_INFO, "EAP-FAST test cases");
+
+	wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / master_secret");
+	if (sha1_t_prf(pac_key, sizeof(pac_key),
+		       "PAC to master secret label hash",
+		       seed, sizeof(seed), buf, sizeof(master_secret)) < 0 ||
+	    os_memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
+		wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+		errors++;
+	}
+
+	wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
+	if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
+			     "key expansion", seed, sizeof(seed),
+			     buf, sizeof(key_block)) ||
+	    os_memcmp(key_block, buf, sizeof(key_block)) != 0) {
+		wpa_printf(MSG_INFO, "PRF test - FAILED!");
+		errors++;
+	}
+
+	wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
+	if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
+		       isk, sizeof(isk), buf, sizeof(imck)) < 0 ||
+	    os_memcmp(imck, buf, sizeof(imck)) != 0) {
+		wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+		errors++;
+	}
+
+	simck = imck;
+	cmk = imck + 40;
+
+	wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / MSK");
+	if (sha1_t_prf(simck, 40, "Session Key Generating Function",
+		       (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+	    os_memcmp(msk, buf, sizeof(msk)) != 0) {
+		wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+		errors++;
+	}
+
+	wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / EMSK");
+	if (sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
+		       (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+	    os_memcmp(emsk, buf, sizeof(emsk)) != 0) {
+		wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+		errors++;
+	}
+
+	wpa_printf(MSG_INFO, "- Compound MAC test case");
+	os_memset(tlv + sizeof(tlv) - 20, 0, 20);
+	if (hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20) < 0 ||
+	    os_memcmp(tlv + sizeof(tlv) - 20, compound_mac,
+		      sizeof(compound_mac)) != 0) {
+		wpa_printf(MSG_INFO, "Compound MAC test - FAILED!");
+		errors++;
+	}
+
+	return errors;
+#else /* EAP_FAST */
+	return 0;
+#endif /* EAP_FAST */
+}
+
+
+static u8 key0[] =
+{
+	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+	0x0b, 0x0b, 0x0b, 0x0b
+};
+static u8 data0[] = "Hi There";
+static u8 prf0[] =
+{
+	0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
+	0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
+	0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
+	0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
+	0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
+	0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
+	0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
+	0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
+};
+
+static u8 key1[] = "Jefe";
+static u8 data1[] = "what do ya want for nothing?";
+static u8 prf1[] =
+{
+	0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
+	0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
+	0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
+	0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
+	0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
+	0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
+	0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
+	0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
+};
+
+
+static u8 key2[] =
+{
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa
+};
+static u8 data2[] =
+{
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	0xdd, 0xdd
+};
+static u8 prf2[] =
+{
+	0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
+	0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
+	0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
+	0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
+	0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
+	0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
+	0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
+	0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
+};
+
+
+struct passphrase_test {
+	char *passphrase;
+	char *ssid;
+	char psk[32];
+};
+
+static struct passphrase_test passphrase_tests[] =
+{
+	{
+		"password",
+		"IEEE",
+		{
+			0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
+			0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
+			0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
+			0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
+		}
+	},
+	{
+		"ThisIsAPassword",
+		"ThisIsASSID",
+		{
+			0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
+			0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
+			0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
+			0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
+		}
+	},
+	{
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+		"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+		{
+			0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
+			0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
+			0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
+			0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
+		}
+	},
+};
+
+#define NUM_PASSPHRASE_TESTS ARRAY_SIZE(passphrase_tests)
+
+
+struct rfc6070_test {
+	char *p;
+	char *s;
+	int c;
+	char dk[32];
+	size_t dk_len;
+};
+
+static struct rfc6070_test rfc6070_tests[] =
+{
+	{
+		"password",
+		"salt",
+		1,
+		{
+			0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+			0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+			0x2f, 0xe0, 0x37, 0xa6
+		},
+		20
+	},
+	{
+		"password",
+		"salt",
+		2,
+		{
+			0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+			0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+			0xd8, 0xde, 0x89, 0x57
+		},
+		20
+	},
+	{
+		"password",
+		"salt",
+		4096,
+		{
+			0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+			0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+			0x65, 0xa4, 0x29, 0xc1
+		},
+		20
+	},
+#if 0 /* This takes quite long to derive.. */
+	{
+		"password",
+		"salt",
+		16777216,
+		{
+			0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+			0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+			0x26, 0x34, 0xe9, 0x84
+		},
+		20
+	},
+#endif
+	{
+		"passwordPASSWORDpassword",
+		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
+		4096,
+		{
+			0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+			0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+			0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+			0x38
+		},
+		25
+	},
+#if 0 /* \0 not currently supported in passphrase parameters.. */
+	{
+		"pass\0word",
+		"sa\0lt",
+		4096,
+		{
+			0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+			0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
+		},
+		16
+	},
+#endif
+};
+
+#define NUM_RFC6070_TESTS ARRAY_SIZE(rfc6070_tests)
+
+
+static int test_sha1(void)
+{
+	u8 res[512];
+	int ret = 0;
+	unsigned int i;
+
+	wpa_printf(MSG_INFO, "PRF-SHA1 test cases:");
+
+	if (sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
+		     res, sizeof(prf0)) == 0 &&
+	    os_memcmp(res, prf0, sizeof(prf0)) == 0)
+		wpa_printf(MSG_INFO, "Test case 0 - OK");
+	else {
+		wpa_printf(MSG_INFO, "Test case 0 - FAILED!");
+		ret++;
+	}
+
+	if (sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
+		     res, sizeof(prf1)) == 0 &&
+	    os_memcmp(res, prf1, sizeof(prf1)) == 0)
+		wpa_printf(MSG_INFO, "Test case 1 - OK");
+	else {
+		wpa_printf(MSG_INFO, "Test case 1 - FAILED!");
+		ret++;
+	}
+
+	if (sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
+		     res, sizeof(prf2)) == 0 &&
+	    os_memcmp(res, prf2, sizeof(prf2)) == 0)
+		wpa_printf(MSG_INFO, "Test case 2 - OK");
+	else {
+		wpa_printf(MSG_INFO, "Test case 2 - FAILED!");
+		ret++;
+	}
+
+	ret += test_eap_fast();
+
+	wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
+	for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
+		u8 psk[32];
+		struct passphrase_test *test = &passphrase_tests[i];
+
+		if (pbkdf2_sha1(test->passphrase,
+				(const u8 *) test->ssid, strlen(test->ssid),
+				4096, psk, 32) == 0 &&
+		    os_memcmp(psk, test->psk, 32) == 0)
+			wpa_printf(MSG_INFO, "Test case %d - OK", i);
+		else {
+			wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+			ret++;
+		}
+	}
+
+	wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
+	for (i = 0; i < NUM_RFC6070_TESTS; i++) {
+		u8 dk[25];
+		struct rfc6070_test *test = &rfc6070_tests[i];
+
+		if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
+				test->c, dk, test->dk_len) == 0 &&
+		    os_memcmp(dk, test->dk, test->dk_len) == 0)
+			wpa_printf(MSG_INFO, "Test case %d - OK", i);
+		else {
+			wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+			ret++;
+		}
+	}
+
+	if (!ret)
+		wpa_printf(MSG_INFO, "SHA1 test cases passed");
+	return ret;
+}
+
+
+struct {
+	char *data;
+	u8 hash[32];
+} tests[] = {
+	{
+		"abc",
+		{
+			0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+			0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+			0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+			0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+		}
+	},
+	{
+		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		{
+			0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+			0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+			0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+			0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+		}
+	}
+};
+
+struct hmac_test {
+	u8 key[80];
+	size_t key_len;
+	u8 data[128];
+	size_t data_len;
+	u8 hash[32];
+} hmac_tests[] = {
+	/* draft-ietf-ipsec-ciph-sha-256-01.txt */
+	{
+		{
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+		},
+		32,
+		"abc", 3,
+		{
+			0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+			0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+			0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+			0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
+		}
+	},
+	{
+		{
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+		},
+		32,
+		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		56,
+		{
+			0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+			0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+			0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+			0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
+		}
+	},
+	{
+		{
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+		},
+		32,
+		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		112,
+		{
+			0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+			0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+			0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+			0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
+		}
+	},
+	{
+		{
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+		},
+		32,
+		"Hi There",
+		8,
+		{
+			0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+			0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+			0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+			0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+		}
+	},
+	{
+		"Jefe",
+		4,
+		"what do ya want for nothing?",
+		28,
+		{
+			0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+			0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+			0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+			0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+		}
+	},
+	{
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+		},
+		32,
+		{
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+			0xdd, 0xdd
+		},
+		50,
+		{
+			0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+			0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+			0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+			0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+		}
+	},
+	{
+		{
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+			0x21, 0x22, 0x23, 0x24, 0x25
+		},
+		37,
+		{
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+			0xcd, 0xcd
+		},
+		50,
+		{
+			0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+			0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+			0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+			0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+		}
+	},
+	{
+		{
+			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+		},
+		32,
+		"Test With Truncation",
+		20,
+		{
+			0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+			0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+			0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+			0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
+		}
+	},
+	{
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+		},
+		80,
+		"Test Using Larger Than Block-Size Key - Hash Key First",
+		54,
+		{
+			0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+			0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+			0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+			0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+		}
+	},
+	{
+		{
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+		},
+		80,
+		"Test Using Larger Than Block-Size Key and Larger Than One "
+		"Block-Size Data",
+		73,
+		{
+			0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+			0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+			0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+			0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+		}
+	}
+};
+
+
+static int test_sha256(void)
+{
+	unsigned int i;
+	u8 hash[32];
+	const u8 *addr[2];
+	size_t len[2];
+	int errors = 0;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
+
+		addr[0] = (u8 *) tests[i].data;
+		len[0] = strlen(tests[i].data);
+		sha256_vector(1, addr, len, hash);
+		if (memcmp(hash, tests[i].hash, 32) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		if (len[0]) {
+			addr[0] = (u8 *) tests[i].data;
+			len[0] = 1;
+			addr[1] = (u8 *) tests[i].data + 1;
+			len[1] = strlen(tests[i].data) - 1;
+			sha256_vector(2, addr, len, hash);
+			if (memcmp(hash, tests[i].hash, 32) != 0) {
+				wpa_printf(MSG_INFO, " FAIL");
+				errors++;
+			} else
+				wpa_printf(MSG_INFO, " OK");
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+		struct hmac_test *t = &hmac_tests[i];
+
+		wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
+
+		if (hmac_sha256(t->key, t->key_len, t->data, t->data_len,
+				hash) < 0 ||
+		    os_memcmp(hash, t->hash, 32) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		addr[0] = t->data;
+		len[0] = t->data_len;
+		if (hmac_sha256_vector(t->key, t->key_len, 1, addr, len,
+				       hash) < 0 ||
+		    os_memcmp(hash, t->hash, 32) != 0) {
+			wpa_printf(MSG_INFO, " FAIL");
+			errors++;
+		} else
+			wpa_printf(MSG_INFO, " OK");
+
+		if (len[0]) {
+			addr[0] = t->data;
+			len[0] = 1;
+			addr[1] = t->data + 1;
+			len[1] = t->data_len - 1;
+			if (hmac_sha256_vector(t->key, t->key_len, 2, addr, len,
+					       hash) < 0 ||
+			    os_memcmp(hash, t->hash, 32) != 0) {
+				wpa_printf(MSG_INFO, " FAIL");
+				errors++;
+			} else
+				wpa_printf(MSG_INFO, " OK");
+		}
+	}
+
+	wpa_printf(MSG_INFO, "Test IEEE 802.11r KDF");
+	sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+		   hash, sizeof(hash));
+	/* TODO: add proper test case for this */
+
+	if (!errors)
+		wpa_printf(MSG_INFO, "SHA256 test cases passed");
+	return errors;
+}
+
+
+static int test_ms_funcs(void)
+{
+	/* Test vector from RFC2759 example */
+	char *username = "User";
+	char *password = "clientPass";
+	u8 auth_challenge[] = {
+		0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+		0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+	};
+	u8 peer_challenge[] = {
+		0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+		0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+	};
+	u8 password_hash[] = {
+		0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
+		0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
+	};
+	u8 nt_response[] = {
+		0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+		0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+		0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+	};
+	u8 password_hash_hash[] = {
+		0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
+		0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
+	};
+	u8 authenticator_response[] = {
+		0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
+		0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
+		0x93, 0x2C, 0xDA, 0x56
+	};
+	u8 master_key[] = {
+		0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
+		0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
+	};
+	u8 send_start_key[] = {
+		0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
+		0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
+	};
+	u8 buf[32];
+	int errors = 0;
+
+	if (nt_password_hash((u8 *) password, os_strlen(password), buf) ||
+	    os_memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
+		wpa_printf(MSG_ERROR, "nt_password_hash failed");
+		errors++;
+	}
+
+	if (generate_nt_response(auth_challenge, peer_challenge,
+				 (u8 *) username, os_strlen(username),
+				 (u8 *) password, os_strlen(password), buf) ||
+	    os_memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
+		wpa_printf(MSG_ERROR, "generate_nt_response failed");
+		errors++;
+	}
+
+	if (hash_nt_password_hash(password_hash, buf) ||
+	    os_memcmp(password_hash_hash, buf,
+		      sizeof(password_hash_hash)) != 0) {
+		wpa_printf(MSG_ERROR, "hash_nt_password_hash failed");
+		errors++;
+	}
+
+	if (generate_authenticator_response((u8 *) password,
+					    os_strlen(password),
+					    peer_challenge, auth_challenge,
+					    (u8 *) username,
+					    os_strlen(username),
+					    nt_response, buf) ||
+	    os_memcmp(authenticator_response, buf,
+		      sizeof(authenticator_response)) != 0) {
+		wpa_printf(MSG_ERROR, "generate_authenticator_response failed");
+		errors++;
+	}
+
+	if (get_master_key(password_hash_hash, nt_response, buf) ||
+	    os_memcmp(master_key, buf, sizeof(master_key)) != 0) {
+		wpa_printf(MSG_ERROR, "get_master_key failed");
+		errors++;
+	}
+
+	if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
+				    1, 1) ||
+	    os_memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
+		wpa_printf(MSG_ERROR, "get_asymetric_start_key failed");
+		errors++;
+	}
+
+	if (errors)
+		wpa_printf(MSG_ERROR, "ms_funcs: %d errors", errors);
+	else
+		wpa_printf(MSG_INFO, "ms_funcs test cases passed");
+
+	return errors;
+}
+
+
+int crypto_module_tests(void)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "crypto module tests");
+	if (test_siv() ||
+	    test_omac1() ||
+	    test_eax() ||
+	    test_cbc() ||
+	    test_ecb() ||
+	    test_key_wrap() ||
+	    test_md5() ||
+	    test_sha1() ||
+	    test_sha256() ||
+	    test_ms_funcs())
+		ret = -1;
+
+	return ret;
+}
diff --git a/src/crypto/crypto_nss.c b/src/crypto/crypto_nss.c
deleted file mode 100644
index acd0a55..0000000
--- a/src/crypto/crypto_nss.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Crypto wrapper functions for NSS
- * Copyright (c) 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 <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prtime.h>
-#include <nspr/prinrval.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nss/sechash.h>
-#include <nss/pk11pub.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-static int nss_hash(HASH_HashType type, unsigned int max_res_len,
-		    size_t num_elem, const u8 *addr[], const size_t *len,
-		    u8 *mac)
-{
-	HASHContext *ctx;
-	size_t i;
-	unsigned int reslen;
-
-	ctx = HASH_Create(type);
-	if (ctx == NULL)
-		return -1;
-
-	HASH_Begin(ctx);
-	for (i = 0; i < num_elem; i++)
-		HASH_Update(ctx, addr[i], len[i]);
-	HASH_End(ctx, mac, &reslen, max_res_len);
-	HASH_Destroy(ctx);
-
-	return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	PK11Context *ctx = NULL;
-	PK11SlotInfo *slot;
-	SECItem *param = NULL;
-	PK11SymKey *symkey = NULL;
-	SECItem item;
-	int olen;
-	u8 pkey[8], next, tmp;
-	int i;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
-	if (slot == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
-		goto out;
-	}
-
-	item.type = siBuffer;
-	item.data = pkey;
-	item.len = 8;
-	symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
-				   CKA_ENCRYPT, &item, NULL);
-	if (symkey == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
-		goto out;
-	}
-
-	param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
-	if (param == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
-		goto out;
-	}
-
-	ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
-					 symkey, param);
-	if (ctx == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
-			   "CKM_DES_ECB) failed");
-		goto out;
-	}
-
-	if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
-	    SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
-		goto out;
-	}
-
-out:
-	if (ctx)
-		PK11_DestroyContext(ctx, PR_TRUE);
-	if (symkey)
-		PK11_FreeSymKey(symkey);
-	if (param)
-		SECITEM_FreeItem(param, PR_TRUE);
-}
-
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
-	     u8 *data, size_t data_len)
-{
-	return -1;
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
-}
-
-
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
-		  u8 *mac)
-{
-	return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	return NULL;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	return NULL;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	return -1;
-}
-
-
-struct crypto_cipher {
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{
-	return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	return -1;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	return -1;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index b4c59d1..9834b25 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
 /*
  * Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -28,19 +28,12 @@
 #include "dh_group5.h"
 #include "sha1.h"
 #include "sha256.h"
+#include "sha384.h"
 #include "crypto.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x00907000
-#define DES_key_schedule des_key_schedule
-#define DES_cblock des_cblock
-#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
-#define DES_ecb_encrypt(input, output, ks, enc) \
-	des_ecb_encrypt((input), (output), *(ks), (enc))
-#endif /* openssl < 0.9.7 */
-
 static BIGNUM * get_group5_prime(void)
 {
-#if OPENSSL_VERSION_NUMBER < 0x00908000 || defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
 	static const unsigned char RFC3526_PRIME_1536[] = {
 		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
 		0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -60,20 +53,11 @@
 		0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
 	};
         return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* openssl < 0.9.8 */
+#else /* OPENSSL_IS_BORINGSSL */
 	return get_rfc3526_prime_1536(NULL);
-#endif /* openssl < 0.9.8 */
+#endif /* OPENSSL_IS_BORINGSSL */
 }
 
-#if OPENSSL_VERSION_NUMBER < 0x00908000
-#ifndef OPENSSL_NO_SHA256
-#ifndef OPENSSL_FIPS
-#define NO_SHA256_WRAPPER
-#endif
-#endif
-
-#endif /* openssl < 0.9.8 */
-
 #ifdef OPENSSL_NO_SHA256
 #define NO_SHA256_WRAPPER
 #endif
@@ -258,7 +242,7 @@
 			   "in AES encrypt", len);
 	}
 	EVP_CIPHER_CTX_cleanup(c);
-	os_free(c);
+	bin_clear_free(c, sizeof(*c));
 }
 
 
@@ -309,7 +293,84 @@
 			   "in AES decrypt", len);
 	}
 	EVP_CIPHER_CTX_cleanup(c);
-	os_free(ctx);
+	bin_clear_free(c, sizeof(*c));
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+	AES_KEY actx;
+	int res;
+
+	if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
+		return -1;
+	res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
+	OPENSSL_cleanse(&actx, sizeof(actx));
+	return res <= 0 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+	       u8 *plain)
+{
+	AES_KEY actx;
+	int res;
+
+	if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
+		return -1;
+	res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
+	OPENSSL_cleanse(&actx, sizeof(actx));
+	return res <= 0 ? -1 : 0;
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	EVP_CIPHER_CTX ctx;
+	int clen, len;
+	u8 buf[16];
+
+	EVP_CIPHER_CTX_init(&ctx);
+	if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+		return -1;
+	EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+	clen = data_len;
+	if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
+	    clen != (int) data_len)
+		return -1;
+
+	len = sizeof(buf);
+	if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+		return -1;
+	EVP_CIPHER_CTX_cleanup(&ctx);
+
+	return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	EVP_CIPHER_CTX ctx;
+	int plen, len;
+	u8 buf[16];
+
+	EVP_CIPHER_CTX_init(&ctx);
+	if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+		return -1;
+	EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+	plen = data_len;
+	if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
+	    plen != (int) data_len)
+		return -1;
+
+	len = sizeof(buf);
+	if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+		return -1;
+	EVP_CIPHER_CTX_cleanup(&ctx);
+
+	return 0;
 }
 
 
@@ -507,8 +568,8 @@
 	return dh;
 
 err:
-	wpabuf_free(pubkey);
-	wpabuf_free(privkey);
+	wpabuf_clear_free(pubkey);
+	wpabuf_clear_free(privkey);
 	DH_free(dh);
 	return NULL;
 }
@@ -581,7 +642,7 @@
 
 err:
 	BN_clear_free(pub_key);
-	wpabuf_free(res);
+	wpabuf_clear_free(res);
 	return NULL;
 }
 
@@ -638,7 +699,7 @@
 	HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
 #else /* openssl < 0.9.9 */
 	if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
-		os_free(ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
 		return NULL;
 	}
 #endif /* openssl < 0.9.9 */
@@ -664,7 +725,7 @@
 		return -2;
 
 	if (mac == NULL || len == NULL) {
-		os_free(ctx);
+		bin_clear_free(ctx, sizeof(*ctx));
 		return 0;
 	}
 
@@ -676,7 +737,7 @@
 	res = HMAC_Final(&ctx->ctx, mac, &mdlen);
 #endif /* openssl < 0.9.9 */
 	HMAC_CTX_cleanup(&ctx->ctx);
-	os_free(ctx);
+	bin_clear_free(ctx, sizeof(*ctx));
 
 	if (res == 1) {
 		*len = mdlen;
@@ -687,43 +748,26 @@
 }
 
 
-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)
+static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
+			       size_t key_len, size_t num_elem,
+			       const u8 *addr[], const size_t *len, u8 *mac,
+			       unsigned int mdlen)
 {
 	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);
+	HMAC_Init_ex(&ctx, key, key_len, type, NULL);
 #else /* openssl < 0.9.9 */
-	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+	if (HMAC_Init_ex(&ctx, key, key_len, type, 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;
@@ -736,6 +780,43 @@
 }
 
 
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector(EVP_md5(), key ,key_len, num_elem, addr, len,
+				   mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+				   ssid_len, iterations, buflen, buf) != 1)
+		return -1;
+	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)
+{
+	return openssl_hmac_vector(EVP_sha1(), key, key_len, num_elem, addr,
+				   len, mac, 20);
+}
+
+
 int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 	       u8 *mac)
 {
@@ -748,32 +829,8 @@
 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;
+	return openssl_hmac_vector(EVP_sha256(), key, key_len, num_elem, addr,
+				   len, mac, 32);
 }
 
 
@@ -786,6 +843,25 @@
 #endif /* CONFIG_SHA256 */
 
 
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
+				   len, mac, 32);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
 int crypto_get_random(void *buf, size_t len)
 {
 	if (RAND_bytes(buf, len) != 1)
@@ -795,8 +871,8 @@
 
 
 #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)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
 {
 	CMAC_CTX *ctx;
 	int ret = -1;
@@ -806,8 +882,15 @@
 	if (ctx == NULL)
 		return -1;
 
-	if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+	if (key_len == 32) {
+		if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
+			goto fail;
+	} else if (key_len == 16) {
+		if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+			goto fail;
+	} else {
 		goto fail;
+	}
 	for (i = 0; i < num_elem; i++) {
 		if (!CMAC_Update(ctx, addr[i], len[i]))
 			goto fail;
@@ -822,10 +905,23 @@
 }
 
 
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
 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);
 }
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
 #endif /* CONFIG_OPENSSL_CMAC */
 
 
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 58e94c3..d3b2631 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1198,14 +1198,14 @@
 	if (dh == NULL)
 		return NULL;
 
-	wpabuf_free(*priv);
+	wpabuf_clear_free(*priv);
 	*priv = wpabuf_alloc(dh->prime_len);
 	if (*priv == NULL)
 		return NULL;
 
 	if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
 	{
-		wpabuf_free(*priv);
+		wpabuf_clear_free(*priv);
 		*priv = NULL;
 		return NULL;
 	}
@@ -1224,7 +1224,7 @@
 			   wpabuf_head(*priv), wpabuf_len(*priv),
 			   dh->prime, dh->prime_len, wpabuf_mhead(pv),
 			   &pv_len) < 0) {
-		wpabuf_free(pv);
+		wpabuf_clear_free(pv);
 		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
 		return NULL;
 	}
@@ -1260,7 +1260,7 @@
 			   wpabuf_head(own_private), wpabuf_len(own_private),
 			   dh->prime, dh->prime_len,
 			   wpabuf_mhead(shared), &shared_len) < 0) {
-		wpabuf_free(shared);
+		wpabuf_clear_free(shared);
 		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
 		return NULL;
 	}
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index d69ecea..fb03efc 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -13,13 +13,21 @@
 #include "crypto.h"
 
 
-static void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u32 *state, const u8 data[64])
 {
 	SHA_CTX context;
 	os_memset(&context, 0, sizeof(context));
-	os_memcpy(&context.h0, state, 5 * 4);
+	context.h0 = state[0];
+	context.h1 = state[1];
+	context.h2 = state[2];
+	context.h3 = state[3];
+	context.h4 = state[4];
 	SHA1_Transform(&context, data);
-	os_memcpy(state, &context.h0, 5 * 4);
+	state[0] = context.h0;
+	state[1] = context.h1;
+	state[2] = context.h2;
+	state[3] = context.h3;
+	state[4] = context.h4;
 }
 
 
@@ -53,7 +61,7 @@
 
 			/* w_i = G(t, XVAL) */
 			os_memcpy(_t, t, 20);
-			sha1_transform((u8 *) _t, xkey);
+			sha1_transform(_t, xkey);
 			_t[0] = host_to_be32(_t[0]);
 			_t[1] = host_to_be32(_t[1]);
 			_t[2] = host_to_be32(_t[2]);
diff --git a/src/crypto/md5.c b/src/crypto/md5.c
index db2b8cc..f64dfd3 100644
--- a/src/crypto/md5.c
+++ b/src/crypto/md5.c
@@ -30,6 +30,7 @@
 	u8 tk[16];
 	const u8 *_addr[6];
 	size_t i, _len[6];
+	int res;
 
 	if (num_elem > 5) {
 		/*
@@ -85,7 +86,10 @@
 	_len[0] = 64;
 	_addr[1] = mac;
 	_len[1] = MD5_MAC_LEN;
-	return md5_vector(2, _addr, _len, mac);
+	res = md5_vector(2, _addr, _len, mac);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memset(tk, 0, sizeof(tk));
+	return res;
 }
 
 
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index 49a5c1c..5f57656 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -78,9 +78,8 @@
  * @challenge: 8-octet Challenge (OUT)
  * Returns: 0 on success, -1 on failure
  */
-static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
-			  const u8 *username, size_t username_len,
-			  u8 *challenge)
+int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+		   const u8 *username, size_t username_len, u8 *challenge)
 {
 	u8 hash[SHA1_MAC_LEN];
 	const unsigned char *addr[3];
diff --git a/src/crypto/ms_funcs.h b/src/crypto/ms_funcs.h
index bd9bfee..b5b5918 100644
--- a/src/crypto/ms_funcs.h
+++ b/src/crypto/ms_funcs.h
@@ -33,6 +33,8 @@
 
 void challenge_response(const u8 *challenge, const u8 *password_hash,
 			u8 *response);
+int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+		   const u8 *username, size_t username_len, u8 *challenge);
 int nt_password_hash(const u8 *password, size_t password_len,
 		     u8 *password_hash);
 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
index 90b9e74..4b2d137 100644
--- a/src/crypto/sha1-prf.c
+++ b/src/crypto/sha1-prf.c
@@ -61,6 +61,7 @@
 		}
 		counter++;
 	}
+	os_memset(hash, 0, sizeof(hash));
 
 	return 0;
 }
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 0effd9b..f9bc0eb 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -95,5 +95,10 @@
 		SHA1_pos++;
 	}
 
+	os_memset(A_MD5, 0, MD5_MAC_LEN);
+	os_memset(P_MD5, 0, MD5_MAC_LEN);
+	os_memset(A_SHA1, 0, SHA1_MAC_LEN);
+	os_memset(P_SHA1, 0, SHA1_MAC_LEN);
+
 	return 0;
 }
diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c
index a529494..562510f 100644
--- a/src/crypto/sha1-tprf.c
+++ b/src/crypto/sha1-tprf.c
@@ -66,5 +66,7 @@
 		len[0] = SHA1_MAC_LEN;
 	}
 
+	os_memset(hash, 0, SHA1_MAC_LEN);
+
 	return 0;
 }
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index d48c77d..8fce139 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -30,6 +30,7 @@
 	unsigned char tk[20];
 	const u8 *_addr[6];
 	size_t _len[6], i;
+	int ret;
 
 	if (num_elem > 5) {
 		/*
@@ -84,7 +85,9 @@
 	_len[0] = 64;
 	_addr[1] = mac;
 	_len[1] = SHA1_MAC_LEN;
-	return sha1_vector(2, _addr, _len, mac);
+	ret = sha1_vector(2, _addr, _len, mac);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	return ret;
 }
 
 
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
index d8a1beb..e7509ce 100644
--- a/src/crypto/sha256-kdf.c
+++ b/src/crypto/sha256-kdf.c
@@ -61,6 +61,7 @@
 
 		if (iter == 255) {
 			os_memset(out, 0, outlen);
+			os_memset(T, 0, SHA256_MAC_LEN);
 			return -1;
 		}
 		iter++;
@@ -68,9 +69,11 @@
 		if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
 		{
 			os_memset(out, 0, outlen);
+			os_memset(T, 0, SHA256_MAC_LEN);
 			return -1;
 		}
 	}
 
+	os_memset(T, 0, SHA256_MAC_LEN);
 	return 0;
 }
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index 9a11208..79791c0 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -95,4 +95,6 @@
 		u8 mask = 0xff << (8 - buf_len_bits % 8);
 		buf[pos - 1] &= mask;
 	}
+
+	os_memset(hash, 0, sizeof(hash));
 }
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
new file mode 100644
index 0000000..e6a1fe4
--- /dev/null
+++ b/src/crypto/sha384.h
@@ -0,0 +1,19 @@
+/*
+ * SHA384 hash implementation and interface functions
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_H
+#define SHA384_H
+
+#define SHA384_MAC_LEN 48
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac);
+
+#endif /* SHA384_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 345ebc7..f9e2e10 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -12,8 +12,6 @@
 struct tls_connection;
 
 struct tls_keys {
-	const u8 *master_key; /* TLS master secret */
-	size_t master_key_len;
 	const u8 *client_random;
 	size_t client_random_len;
 	const u8 *server_random;
@@ -41,9 +39,13 @@
 	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 	TLS_FAIL_BAD_CERTIFICATE = 7,
 	TLS_FAIL_SERVER_CHAIN_PROBE = 8,
-	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
+	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+	TLS_FAIL_DOMAIN_MISMATCH = 10,
 };
 
+
+#define TLS_MAX_ALT_SUBJECT 10
+
 union tls_event_data {
 	struct {
 		int depth;
@@ -59,6 +61,8 @@
 		const struct wpabuf *cert;
 		const u8 *hash;
 		size_t hash_len;
+		const char *altsubject[TLS_MAX_ALT_SUBJECT];
+		int num_altsubject;
 	} peer_cert;
 
 	struct {
@@ -102,7 +106,11 @@
  * @altsubject_match: String to match in the alternative subject of the peer
  * certificate or %NULL to allow all alternative subjects
  * @suffix_match: String to suffix match in the dNSName or CN of the peer
- * certificate or %NULL to allow all domain names
+ * certificate or %NULL to allow all domain names. This may allow subdomains an
+ * wildcard certificates. Each domain name label must have a full match.
+ * @domain_match: String to match in the dNSName or CN of the peer
+ * certificate or %NULL to allow all domain names. This requires a full,
+ * case-insensitive match.
  * @client_cert: File or reference name for client X.509 certificate in PEM or
  * DER format
  * @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -146,6 +154,7 @@
 	const char *subject_match;
 	const char *altsubject_match;
 	const char *suffix_match;
+	const char *domain_match;
 	const char *client_cert;
 	const u8 *client_cert_blob;
 	size_t client_cert_blob_len;
@@ -297,10 +306,10 @@
 					   int verify_peer);
 
 /**
- * tls_connection_get_keys - Get master key and random data from TLS connection
+ * tls_connection_get_keys - Get random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- * @keys: Structure of key/random data (filled on success)
+ * @keys: Structure of client/server random data (filled on success)
  * Returns: 0 on success, -1 on failure
  */
 int __must_check tls_connection_get_keys(void *tls_ctx,
@@ -314,6 +323,7 @@
  * @label: Label (e.g., description of the key) for PRF
  * @server_random_first: seed is 0 = client_random|server_random,
  * 1 = server_random|client_random
+ * @skip_keyblock: Skip TLS key block from the beginning of PRF output
  * @out: Buffer for output data from TLS-PRF
  * @out_len: Length of the output buffer
  * Returns: 0 on success, -1 on failure
@@ -331,6 +341,7 @@
 				     struct tls_connection *conn,
 				     const char *label,
 				     int server_random_first,
+				     int skip_keyblock,
 				     u8 *out, size_t out_len);
 
 /**
@@ -517,16 +528,6 @@
 				    struct tls_connection *conn);
 
 /**
- * tls_connection_get_keyblock_size - Get TLS key_block size
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn);
-
-/**
  * tls_capabilities - Get supported TLS capabilities
  * @tls_ctx: TLS context data from tls_init()
  * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
@@ -556,4 +557,6 @@
 
 void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
 
+int tls_get_library_version(char *buf, size_t buf_len);
+
 #endif /* TLS_H */
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 20d0a31..c7f6464 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -12,61 +12,15 @@
 #ifdef PKCS12_FUNCS
 #include <gnutls/pkcs12.h>
 #endif /* PKCS12_FUNCS */
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+#include <gnutls/ocsp.h>
+#endif /* 3.1.3 */
 
 #include "common.h"
+#include "crypto/crypto.h"
 #include "tls.h"
 
 
-#define WPA_TLS_RANDOM_SIZE 32
-#define WPA_TLS_MASTER_SIZE 48
-
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x010302
-/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
- * use of internal structures to get the master_secret and
- * {server,client}_random.
- */
-#define GNUTLS_INTERNAL_STRUCTURE_HACK
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-/*
- * It looks like gnutls does not provide access to client/server_random and
- * master_key. This is somewhat unfortunate since these are needed for key
- * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
- * hack that copies the gnutls_session_int definition from gnutls_int.h so that
- * we can get the needed information.
- */
-
-typedef u8 uint8;
-typedef unsigned char opaque;
-typedef struct {
-    uint8 suite[2];
-} cipher_suite_st;
-
-typedef struct {
-	gnutls_connection_end_t entity;
-	gnutls_kx_algorithm_t kx_algorithm;
-	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
-	gnutls_mac_algorithm_t read_mac_algorithm;
-	gnutls_compression_method_t read_compression_algorithm;
-	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
-	gnutls_mac_algorithm_t write_mac_algorithm;
-	gnutls_compression_method_t write_compression_algorithm;
-	cipher_suite_st current_cipher_suite;
-	opaque master_secret[WPA_TLS_MASTER_SIZE];
-	opaque client_random[WPA_TLS_RANDOM_SIZE];
-	opaque server_random[WPA_TLS_RANDOM_SIZE];
-	/* followed by stuff we are not interested in */
-} security_parameters_st;
-
-struct gnutls_session_int {
-	security_parameters_st security_parameters;
-	/* followed by things we are not interested in */
-};
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
 static int tls_gnutls_ref_count = 0;
 
 struct tls_global {
@@ -78,17 +32,23 @@
 
 	int params_set;
 	gnutls_certificate_credentials_t xcred;
+
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
 };
 
 struct tls_connection {
+	struct tls_global *global;
 	gnutls_session_t session;
-	char *subject_match, *altsubject_match;
 	int read_alerts, write_alerts, failed;
 
 	u8 *pre_shared_secret;
 	size_t pre_shared_secret_len;
 	int established;
 	int verify_peer;
+	unsigned int disable_time_checks:1;
 
 	struct wpabuf *push_buf;
 	struct wpabuf *pull_buf;
@@ -96,9 +56,16 @@
 
 	int params_set;
 	gnutls_certificate_credentials_t xcred;
+
+	char *suffix_match;
+	char *domain_match;
+	unsigned int flags;
 };
 
 
+static int tls_connection_verify_peer(gnutls_session_t session);
+
+
 static void tls_log_func(int level, const char *msg)
 {
 	char *s, *pos;
@@ -129,17 +96,11 @@
 {
 	struct tls_global *global;
 
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	/* Because of the horrible hack to get master_secret and client/server
-	 * random, we need to make sure that the gnutls version is something
-	 * that is expected to have same structure definition for the session
-	 * data.. */
-	const char *ver;
-	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
-				 "1.3.2",
-				 NULL };
-	int i;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+	if (tls_gnutls_ref_count == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: Library version %s (runtime) - %s (build)",
+			   gnutls_check_version(NULL), GNUTLS_VERSION);
+	}
 
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
@@ -151,28 +112,16 @@
 	}
 	tls_gnutls_ref_count++;
 
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	ver = gnutls_check_version(NULL);
-	if (ver == NULL) {
-		tls_deinit(global);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
-	for (i = 0; ok_ver[i]; i++) {
-		if (strcmp(ok_ver[i], ver) == 0)
-			break;
-	}
-	if (ok_ver[i] == NULL) {
-		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
-			   "to be tested and enabled in tls_gnutls.c", ver);
-		tls_deinit(global);
-		return NULL;
-	}
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
 	gnutls_global_set_log_function(tls_log_func);
 	if (wpa_debug_show_keys)
 		gnutls_global_set_log_level(11);
+
+	if (conf) {
+		global->event_cb = conf->event_cb;
+		global->cb_ctx = conf->cb_ctx;
+		global->cert_in_cb = conf->cert_in_cb;
+	}
+
 	return global;
 }
 
@@ -246,12 +195,7 @@
 static int tls_gnutls_init_session(struct tls_global *global,
 				   struct tls_connection *conn)
 {
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
 	const char *err;
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
-	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
-	const int protos[2] = { GNUTLS_TLS1, 0 };
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 	int ret;
 
 	ret = gnutls_init(&conn->session,
@@ -266,7 +210,6 @@
 	if (ret < 0)
 		goto fail;
 
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
 	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
 					 &err);
 	if (ret < 0) {
@@ -274,19 +217,11 @@
 			   "'%s'", err);
 		goto fail;
 	}
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
-	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
-	if (ret < 0)
-		goto fail;
-
-	ret = gnutls_protocol_set_priority(conn->session, protos);
-	if (ret < 0)
-		goto fail;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 
 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
 	gnutls_transport_set_push_function(conn->session, tls_push_func);
 	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
+	gnutls_session_set_ptr(conn->session, conn);
 
 	return 0;
 
@@ -307,6 +242,7 @@
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 		return NULL;
+	conn->global = global;
 
 	if (tls_gnutls_init_session(global, conn)) {
 		os_free(conn);
@@ -342,10 +278,10 @@
 	gnutls_certificate_free_credentials(conn->xcred);
 	gnutls_deinit(conn->session);
 	os_free(conn->pre_shared_secret);
-	os_free(conn->subject_match);
-	os_free(conn->altsubject_match);
 	wpabuf_free(conn->push_buf);
 	wpabuf_free(conn->pull_buf);
+	os_free(conn->suffix_match);
+	os_free(conn->domain_match);
 	os_free(conn);
 }
 
@@ -403,104 +339,6 @@
 }
 
 
-#if 0
-static int tls_match_altsubject(X509 *cert, const char *match)
-{
-	GENERAL_NAME *gen;
-	char *field, *tmp;
-	void *ext;
-	int i, found = 0;
-	size_t len;
-
-	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-
-	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
-		gen = sk_GENERAL_NAME_value(ext, i);
-		switch (gen->type) {
-		case GEN_EMAIL:
-			field = "EMAIL";
-			break;
-		case GEN_DNS:
-			field = "DNS";
-			break;
-		case GEN_URI:
-			field = "URI";
-			break;
-		default:
-			field = NULL;
-			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
-				   "unsupported type=%d", gen->type);
-			break;
-		}
-
-		if (!field)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
-			   field, gen->d.ia5->data);
-		len = os_strlen(field) + 1 +
-			strlen((char *) gen->d.ia5->data) + 1;
-		tmp = os_malloc(len);
-		if (tmp == NULL)
-			continue;
-		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
-		if (strstr(tmp, match))
-			found++;
-		os_free(tmp);
-	}
-
-	return found;
-}
-#endif
-
-
-#if 0
-static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
-{
-	char buf[256];
-	X509 *err_cert;
-	int err, depth;
-	SSL *ssl;
-	struct tls_connection *conn;
-	char *match, *altmatch;
-
-	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
-	err = X509_STORE_CTX_get_error(x509_ctx);
-	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
-	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
-					 SSL_get_ex_data_X509_STORE_CTX_idx());
-	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
-
-	conn = SSL_get_app_data(ssl);
-	match = conn ? conn->subject_match : NULL;
-	altmatch = conn ? conn->altsubject_match : NULL;
-
-	if (!preverify_ok) {
-		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
-			   " error %d (%s) depth %d for '%s'", err,
-			   X509_verify_cert_error_string(err), depth, buf);
-	} else {
-		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
-			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
-			   preverify_ok, err,
-			   X509_verify_cert_error_string(err), depth, buf);
-		if (depth == 0 && match && strstr(buf, match) == NULL) {
-			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
-				   "match with '%s'", buf, match);
-			preverify_ok = 0;
-		} else if (depth == 0 && altmatch &&
-			   !tls_match_altsubject(err_cert, altmatch)) {
-			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
-				   "'%s' not found", altmatch);
-			preverify_ok = 0;
-		}
-	}
-
-	return preverify_ok;
-}
-#endif
-
-
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
 {
@@ -509,86 +347,142 @@
 	if (conn == NULL || params == NULL)
 		return -1;
 
-	os_free(conn->subject_match);
-	conn->subject_match = NULL;
 	if (params->subject_match) {
-		conn->subject_match = os_strdup(params->subject_match);
-		if (conn->subject_match == NULL)
+		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
+		return -1;
+	}
+
+	if (params->altsubject_match) {
+		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
+		return -1;
+	}
+
+	os_free(conn->suffix_match);
+	conn->suffix_match = NULL;
+	if (params->suffix_match) {
+		conn->suffix_match = os_strdup(params->suffix_match);
+		if (conn->suffix_match == NULL)
 			return -1;
 	}
 
-	os_free(conn->altsubject_match);
-	conn->altsubject_match = NULL;
-	if (params->altsubject_match) {
-		conn->altsubject_match = os_strdup(params->altsubject_match);
-		if (conn->altsubject_match == NULL)
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+	os_free(conn->domain_match);
+	conn->domain_match = NULL;
+	if (params->domain_match) {
+		conn->domain_match = os_strdup(params->domain_match);
+		if (conn->domain_match == NULL)
 			return -1;
 	}
+#else /* < 3.3.0 */
+	if (params->domain_match) {
+		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
+		return -1;
+	}
+#endif /* >= 3.3.0 */
+
+	conn->flags = params->flags;
+
+	if (params->openssl_ciphers) {
+		wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+		return -1;
+	}
 
 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
 	 * to force peer validation(?) */
 
 	if (params->ca_cert) {
-		conn->verify_peer = 1;
+		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
+			   params->ca_cert);
 		ret = gnutls_certificate_set_x509_trust_file(
-			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
 		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
-				   "in PEM format: %s", params->ca_cert,
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
+				   params->ca_cert,
 				   gnutls_strerror(ret));
 			ret = gnutls_certificate_set_x509_trust_file(
 				conn->xcred, params->ca_cert,
-				GNUTLS_X509_FMT_DER);
+				GNUTLS_X509_FMT_PEM);
 			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
-					   "'%s' in DER format: %s",
+				wpa_printf(MSG_DEBUG,
+					   "Failed to read CA cert '%s' in PEM format: %s",
 					   params->ca_cert,
 					   gnutls_strerror(ret));
 				return -1;
 			}
 		}
+	} else if (params->ca_cert_blob) {
+		gnutls_datum_t ca;
+
+		ca.data = (unsigned char *) params->ca_cert_blob;
+		ca.size = params->ca_cert_blob_len;
+
+		ret = gnutls_certificate_set_x509_trust_mem(
+			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "Failed to parse CA cert in DER format: %s",
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_mem(
+				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "Failed to parse CA cert in PEM format: %s",
+					   gnutls_strerror(ret));
+				return -1;
+			}
+		}
+	} else if (params->ca_path) {
+		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
+		return -1;
+	}
+
+	conn->disable_time_checks = 0;
+	if (params->ca_cert || params->ca_cert_blob) {
+		conn->verify_peer = 1;
+		gnutls_certificate_set_verify_function(
+			conn->xcred, tls_connection_verify_peer);
 
 		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
 			gnutls_certificate_set_verify_flags(
 				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+			conn->disable_time_checks = 1;
 			gnutls_certificate_set_verify_flags(
 				conn->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
 #if GNUTLS_VERSION_NUMBER >= 0x03010b
 		ret = gnutls_certificate_set_x509_key_file2(
 			conn->xcred, params->client_cert, params->private_key,
-			GNUTLS_X509_FMT_PEM, params->private_key_passwd, 0);
+			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
 #else
 		/* private_key_passwd not (easily) supported here */
 		ret = gnutls_certificate_set_x509_key_file(
 			conn->xcred, params->client_cert, params->private_key,
-			GNUTLS_X509_FMT_PEM);
+			GNUTLS_X509_FMT_DER);
 #endif
 		if (ret < 0) {
 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
-				   "in PEM format: %s", gnutls_strerror(ret));
+				   "in DER format: %s", gnutls_strerror(ret));
 #if GNUTLS_VERSION_NUMBER >= 0x03010b
 			ret = gnutls_certificate_set_x509_key_file2(
 				conn->xcred, params->client_cert,
-				params->private_key, GNUTLS_X509_FMT_DER,
+				params->private_key, GNUTLS_X509_FMT_PEM,
 				params->private_key_passwd, 0);
 #else
 			ret = gnutls_certificate_set_x509_key_file(
 				conn->xcred, params->client_cert,
-				params->private_key, GNUTLS_X509_FMT_DER);
+				params->private_key, GNUTLS_X509_FMT_PEM);
 #endif
 			if (ret < 0) {
 				wpa_printf(MSG_DEBUG, "Failed to read client "
-					   "cert/key in DER format: %s",
+					   "cert/key in PEM format: %s",
 					   gnutls_strerror(ret));
 				return ret;
 			}
@@ -597,7 +491,6 @@
 		int pkcs12_ok = 0;
 #ifdef PKCS12_FUNCS
 		/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
 			params->private_key_passwd);
@@ -607,7 +500,6 @@
 			return -1;
 		} else
 			pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
 #endif /* PKCS12_FUNCS */
 
 		if (!pkcs12_ok) {
@@ -615,8 +507,82 @@
 				   "included");
 			return -1;
 		}
+	} else if (params->client_cert_blob && params->private_key_blob) {
+		gnutls_datum_t cert, key;
+
+		cert.data = (unsigned char *) params->client_cert_blob;
+		cert.size = params->client_cert_blob_len;
+		key.data = (unsigned char *) params->private_key_blob;
+		key.size = params->private_key_blob_len;
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+		ret = gnutls_certificate_set_x509_key_mem2(
+			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
+			params->private_key_passwd, 0);
+#else
+		/* private_key_passwd not (easily) supported here */
+		ret = gnutls_certificate_set_x509_key_mem(
+			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
+#endif
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in DER format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+			ret = gnutls_certificate_set_x509_key_mem2(
+				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
+				params->private_key_passwd, 0);
+#else
+			/* private_key_passwd not (easily) supported here */
+			ret = gnutls_certificate_set_x509_key_mem(
+				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
+#endif
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in PEM format: %s",
+					   gnutls_strerror(ret));
+				return ret;
+			}
+		}
+	} else if (params->private_key_blob) {
+#ifdef PKCS12_FUNCS
+		gnutls_datum_t key;
+
+		key.data = (unsigned char *) params->private_key_blob;
+		key.size = params->private_key_blob_len;
+
+		/* Try to load in PKCS#12 format */
+		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
+			conn->xcred, &key, GNUTLS_X509_FMT_DER,
+			params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			return -1;
+		}
+#else /* PKCS12_FUNCS */
+		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
+		return -1;
+#endif /* PKCS12_FUNCS */
 	}
 
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
+		ret = gnutls_ocsp_status_request_enable_client(conn->session,
+							       NULL, 0, NULL);
+		if (ret != GNUTLS_E_SUCCESS) {
+			wpa_printf(MSG_INFO,
+				   "GnuTLS: Failed to enable OCSP client");
+			return -1;
+		}
+	}
+#else /* 3.1.3 */
+	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+		wpa_printf(MSG_INFO,
+			   "GnuTLS: OCSP not supported by this version of GnuTLS");
+		return -1;
+	}
+#endif /* 3.1.3 */
+
 	conn->params_set = 1;
 
 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -654,17 +620,17 @@
 
 	if (params->ca_cert) {
 		ret = gnutls_certificate_set_x509_trust_file(
-			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
 		if (ret < 0) {
 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
-				   "in PEM format: %s", params->ca_cert,
+				   "in DER format: %s", params->ca_cert,
 				   gnutls_strerror(ret));
 			ret = gnutls_certificate_set_x509_trust_file(
 				global->xcred, params->ca_cert,
-				GNUTLS_X509_FMT_DER);
+				GNUTLS_X509_FMT_PEM);
 			if (ret < 0) {
 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
-					   "'%s' in DER format: %s",
+					   "'%s' in PEM format: %s",
 					   params->ca_cert,
 					   gnutls_strerror(ret));
 				goto fail;
@@ -677,29 +643,27 @@
 				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
 			gnutls_certificate_set_verify_flags(
 				global->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
 		/* TODO: private_key_passwd? */
 		ret = gnutls_certificate_set_x509_key_file(
 			global->xcred, params->client_cert,
-			params->private_key, GNUTLS_X509_FMT_PEM);
+			params->private_key, GNUTLS_X509_FMT_DER);
 		if (ret < 0) {
 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
-				   "in PEM format: %s", gnutls_strerror(ret));
+				   "in DER format: %s", gnutls_strerror(ret));
 			ret = gnutls_certificate_set_x509_key_file(
 				global->xcred, params->client_cert,
-				params->private_key, GNUTLS_X509_FMT_DER);
+				params->private_key, GNUTLS_X509_FMT_PEM);
 			if (ret < 0) {
 				wpa_printf(MSG_DEBUG, "Failed to read client "
-					   "cert/key in DER format: %s",
+					   "cert/key in PEM format: %s",
 					   gnutls_strerror(ret));
 				goto fail;
 			}
@@ -708,7 +672,6 @@
 		int pkcs12_ok = 0;
 #ifdef PKCS12_FUNCS
 		/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
 			global->xcred, params->private_key,
 			GNUTLS_X509_FMT_DER, params->private_key_passwd);
@@ -718,7 +681,6 @@
 			goto fail;
 		} else
 			pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
 #endif /* PKCS12_FUNCS */
 
 		if (!pkcs12_ok) {
@@ -763,124 +725,341 @@
 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	security_parameters_st *sec;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#if GNUTLS_VERSION_NUMBER >= 0x030012
+	gnutls_datum_t client, server;
 
 	if (conn == NULL || conn->session == NULL || keys == NULL)
 		return -1;
 
 	os_memset(keys, 0, sizeof(*keys));
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	sec = &conn->session->security_parameters;
-	keys->master_key = sec->master_secret;
-	keys->master_key_len = WPA_TLS_MASTER_SIZE;
-	keys->client_random = sec->client_random;
-	keys->server_random = sec->server_random;
-#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-	keys->client_random =
-		(u8 *) gnutls_session_get_client_random(conn->session);
-	keys->server_random =
-		(u8 *) gnutls_session_get_server_random(conn->session);
-	/* No access to master_secret */
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
-	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
-	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+	gnutls_session_get_random(conn->session, &client, &server);
+	keys->client_random = client.data;
+	keys->server_random = server.data;
+	keys->client_random_len = client.size;
+	keys->server_random_len = client.size;
 
 	return 0;
+#else /* 3.0.18 */
+	return -1;
+#endif /* 3.0.18 */
 }
 
 
 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
+		       int skip_keyblock, u8 *out, size_t out_len)
 {
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-	if (conn == NULL || conn->session == NULL)
+	if (conn == NULL || conn->session == NULL || skip_keyblock)
 		return -1;
 
 	return gnutls_prf(conn->session, os_strlen(label), label,
 			  server_random_first, 0, NULL, out_len, (char *) out);
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-	return -1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
 }
 
 
-static int tls_connection_verify_peer(struct tls_connection *conn,
-				      gnutls_alert_description_t *err)
+static void gnutls_tls_fail_event(struct tls_connection *conn,
+				  const gnutls_datum_t *cert, int depth,
+				  const char *subject, const char *err_str,
+				  enum tls_fail_reason reason)
 {
+	union tls_event_data ev;
+	struct tls_global *global = conn->global;
+	struct wpabuf *cert_buf = NULL;
+
+	if (global->event_cb == NULL)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	ev.cert_fail.depth = depth;
+	ev.cert_fail.subject = subject ? subject : "";
+	ev.cert_fail.reason = reason;
+	ev.cert_fail.reason_txt = err_str;
+	if (cert) {
+		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
+		ev.cert_fail.cert = cert_buf;
+	}
+	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	wpabuf_free(cert_buf);
+}
+
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+static int server_eku_purpose(gnutls_x509_crt_t cert)
+{
+	unsigned int i;
+
+	for (i = 0; ; i++) {
+		char oid[128];
+		size_t oid_size = sizeof(oid);
+		int res;
+
+		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
+							  &oid_size, NULL);
+		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+			if (i == 0) {
+				/* No EKU - assume any use allowed */
+				return 1;
+			}
+			break;
+		}
+
+		if (res < 0) {
+			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
+			return 0;
+		}
+
+		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
+		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
+		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+#endif /* < 3.3.0 */
+
+
+static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
+		      gnutls_alert_description_t *err)
+{
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+	gnutls_datum_t response, buf;
+	gnutls_ocsp_resp_t resp;
+	unsigned int cert_status;
+	int res;
+
+	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
+		return 0;
+
+	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
+		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+			wpa_printf(MSG_INFO,
+				   "GnuTLS: No valid OCSP response received");
+			goto ocsp_error;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
+		return 0;
+	}
+
+	/*
+	 * GnuTLS has already verified the OCSP response in
+	 * check_ocsp_response() and rejected handshake if the certificate was
+	 * found to be revoked. However, if the response indicates that the
+	 * status is unknown, handshake continues and reaches here. We need to
+	 * re-import the OCSP response to check for unknown certificate status,
+	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
+	 * gnutls_ocsp_resp_verify_direct() calls.
+	 */
+
+	res = gnutls_ocsp_status_request_get(session, &response);
+	if (res != GNUTLS_E_SUCCESS) {
+		wpa_printf(MSG_INFO,
+			   "GnuTLS: OCSP response was received, but it was not valid");
+		goto ocsp_error;
+	}
+
+	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
+		goto ocsp_error;
+
+	res = gnutls_ocsp_resp_import(resp, &response);
+	if (res != GNUTLS_E_SUCCESS) {
+		wpa_printf(MSG_INFO,
+			   "GnuTLS: Could not parse received OCSP response: %s",
+			   gnutls_strerror(res));
+		gnutls_ocsp_resp_deinit(resp);
+		goto ocsp_error;
+	}
+
+	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
+	if (res == GNUTLS_E_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
+		gnutls_free(buf.data);
+	}
+
+	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
+					  NULL, &cert_status, NULL,
+					  NULL, NULL, NULL);
+	gnutls_ocsp_resp_deinit(resp);
+	if (res != GNUTLS_E_SUCCESS) {
+		wpa_printf(MSG_INFO,
+			   "GnuTLS: Failed to extract OCSP information: %s",
+			   gnutls_strerror(res));
+		goto ocsp_error;
+	}
+
+	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
+		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
+	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: OCSP cert status: revoked");
+		goto ocsp_error;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: OCSP cert status: unknown");
+		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
+			goto ocsp_error;
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: OCSP was not required, so allow connection to continue");
+	}
+
+	return 0;
+
+ocsp_error:
+	gnutls_tls_fail_event(conn, NULL, 0, NULL,
+			      "bad certificate status response",
+			      TLS_FAIL_REVOKED);
+	*err = GNUTLS_A_CERTIFICATE_REVOKED;
+	return -1;
+#else /* GnuTLS 3.1.3 or newer */
+	return 0;
+#endif /* GnuTLS 3.1.3 or newer */
+}
+
+
+static int tls_connection_verify_peer(gnutls_session_t session)
+{
+	struct tls_connection *conn;
 	unsigned int status, num_certs, i;
 	struct os_time now;
 	const gnutls_datum_t *certs;
 	gnutls_x509_crt_t cert;
+	gnutls_alert_description_t err;
+	int res;
 
-	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+	conn = gnutls_session_get_ptr(session);
+	if (!conn->verify_peer) {
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: No peer certificate verification enabled");
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+	{
+		gnutls_typed_vdata_st data[1];
+		unsigned int elements = 0;
+
+		os_memset(data, 0, sizeof(data));
+		if (!conn->global->server) {
+			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
+			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
+			elements++;
+		}
+		res = gnutls_certificate_verify_peers(session, data, 1,
+						      &status);
+	}
+#else /* < 3.3.0 */
+	res = gnutls_certificate_verify_peers2(session, &status);
+#endif
+	if (res < 0) {
 		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
 			   "certificate chain");
-		*err = GNUTLS_A_INTERNAL_ERROR;
-		return -1;
+		err = GNUTLS_A_INTERNAL_ERROR;
+		goto out;
+	}
+
+#if GNUTLS_VERSION_NUMBER >= 0x030104
+	{
+		gnutls_datum_t info;
+		int ret, type;
+
+		type = gnutls_certificate_type_get(session);
+		ret = gnutls_certificate_verification_status_print(status, type,
+								   &info, 0);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Failed to print verification status");
+			err = GNUTLS_A_INTERNAL_ERROR;
+			goto out;
+		}
+		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
+		gnutls_free(info.data);
+	}
+#endif /* GnuTLS 3.1.4 or newer */
+
+	certs = gnutls_certificate_get_peers(session, &num_certs);
+	if (certs == NULL || num_certs == 0) {
+		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
+		err = GNUTLS_A_UNKNOWN_CA;
+		goto out;
 	}
 
 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
-		*err = GNUTLS_A_INTERNAL_ERROR;
 		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
 				   "algorithm");
-			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
+			gnutls_tls_fail_event(conn, NULL, 0, NULL,
+					      "certificate uses insecure algorithm",
+					      TLS_FAIL_BAD_CERTIFICATE);
+			err = GNUTLS_A_INSUFFICIENT_SECURITY;
+			goto out;
 		}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
 			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
 				   "activated");
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			gnutls_tls_fail_event(conn, NULL, 0, NULL,
+					      "certificate not yet valid",
+					      TLS_FAIL_NOT_YET_VALID);
+			err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			goto out;
 		}
 		if (status & GNUTLS_CERT_EXPIRED) {
 			wpa_printf(MSG_INFO, "TLS: Certificate expired");
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			gnutls_tls_fail_event(conn, NULL, 0, NULL,
+					      "certificate has expired",
+					      TLS_FAIL_EXPIRED);
+			err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			goto out;
 		}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
-		return -1;
+		gnutls_tls_fail_event(conn, NULL, 0, NULL,
+				      "untrusted certificate",
+				      TLS_FAIL_UNTRUSTED);
+		err = GNUTLS_A_INTERNAL_ERROR;
+		goto out;
 	}
 
 	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
 		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
 			   "known issuer");
-		*err = GNUTLS_A_UNKNOWN_CA;
-		return -1;
+		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
+				      TLS_FAIL_UNTRUSTED);
+		err = GNUTLS_A_UNKNOWN_CA;
+		goto out;
 	}
 
 	if (status & GNUTLS_CERT_REVOKED) {
 		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
-		*err = GNUTLS_A_CERTIFICATE_REVOKED;
-		return -1;
+		gnutls_tls_fail_event(conn, NULL, 0, NULL,
+				      "certificate revoked",
+				      TLS_FAIL_REVOKED);
+		err = GNUTLS_A_CERTIFICATE_REVOKED;
+		goto out;
 	}
 
+	if (status != 0) {
+		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
+			   status);
+		err = GNUTLS_A_INTERNAL_ERROR;
+		goto out;
+	}
+
+	if (check_ocsp(conn, session, &err))
+		goto out;
+
 	os_get_time(&now);
 
-	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
-	if (certs == NULL) {
-		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
-			   "received");
-		*err = GNUTLS_A_UNKNOWN_CA;
-		return -1;
-	}
-
 	for (i = 0; i < num_certs; i++) {
 		char *buf;
 		size_t len;
 		if (gnutls_x509_crt_init(&cert) < 0) {
 			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
 				   "failed");
-			*err = GNUTLS_A_BAD_CERTIFICATE;
-			return -1;
+			err = GNUTLS_A_BAD_CERTIFICATE;
+			goto out;
 		}
 
 		if (gnutls_x509_crt_import(cert, &certs[i],
@@ -888,8 +1067,8 @@
 			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
 				   "certificate %d/%d", i + 1, num_certs);
 			gnutls_x509_crt_deinit(cert);
-			*err = GNUTLS_A_BAD_CERTIFICATE;
-			return -1;
+			err = GNUTLS_A_BAD_CERTIFICATE;
+			goto out;
 		}
 
 		gnutls_x509_crt_get_dn(cert, NULL, &len);
@@ -902,26 +1081,128 @@
 		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
 			   i + 1, num_certs, buf);
 
+		if (conn->global->event_cb) {
+			struct wpabuf *cert_buf = NULL;
+			union tls_event_data ev;
+#ifdef CONFIG_SHA256
+			u8 hash[32];
+			const u8 *_addr[1];
+			size_t _len[1];
+#endif /* CONFIG_SHA256 */
+
+			os_memset(&ev, 0, sizeof(ev));
+			if (conn->global->cert_in_cb) {
+				cert_buf = wpabuf_alloc_copy(certs[i].data,
+							     certs[i].size);
+				ev.peer_cert.cert = cert_buf;
+			}
+#ifdef CONFIG_SHA256
+			_addr[0] = certs[i].data;
+			_len[0] = certs[i].size;
+			if (sha256_vector(1, _addr, _len, hash) == 0) {
+				ev.peer_cert.hash = hash;
+				ev.peer_cert.hash_len = sizeof(hash);
+			}
+#endif /* CONFIG_SHA256 */
+			ev.peer_cert.depth = i;
+			ev.peer_cert.subject = buf;
+			conn->global->event_cb(conn->global->cb_ctx,
+					       TLS_PEER_CERTIFICATE, &ev);
+			wpabuf_free(cert_buf);
+		}
+
 		if (i == 0) {
-			/* TODO: validate subject_match and altsubject_match */
+			if (conn->suffix_match &&
+			    !gnutls_x509_crt_check_hostname(
+				    cert, conn->suffix_match)) {
+				wpa_printf(MSG_WARNING,
+					   "TLS: Domain suffix match '%s' not found",
+					   conn->suffix_match);
+				gnutls_tls_fail_event(
+					conn, &certs[i], i, buf,
+					"Domain suffix mismatch",
+					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+				err = GNUTLS_A_BAD_CERTIFICATE;
+				gnutls_x509_crt_deinit(cert);
+				os_free(buf);
+				goto out;
+			}
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+			if (conn->domain_match &&
+			    !gnutls_x509_crt_check_hostname2(
+				    cert, conn->domain_match,
+				    GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+				wpa_printf(MSG_WARNING,
+					   "TLS: Domain match '%s' not found",
+					   conn->domain_match);
+				gnutls_tls_fail_event(
+					conn, &certs[i], i, buf,
+					"Domain mismatch",
+					TLS_FAIL_DOMAIN_MISMATCH);
+				err = GNUTLS_A_BAD_CERTIFICATE;
+				gnutls_x509_crt_deinit(cert);
+				os_free(buf);
+				goto out;
+			}
+#endif /* >= 3.3.0 */
+
+			/* TODO: validate altsubject_match.
+			 * For now, any such configuration is rejected in
+			 * tls_connection_set_params() */
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+			/*
+			 * gnutls_certificate_verify_peers() not available, so
+			 * need to check EKU separately.
+			 */
+			if (!conn->global->server &&
+			    !server_eku_purpose(cert)) {
+				wpa_printf(MSG_WARNING,
+					   "GnuTLS: No server EKU");
+				gnutls_tls_fail_event(
+					conn, &certs[i], i, buf,
+					"No server EKU",
+					TLS_FAIL_BAD_CERTIFICATE);
+				err = GNUTLS_A_BAD_CERTIFICATE;
+				gnutls_x509_crt_deinit(cert);
+				os_free(buf);
+				goto out;
+			}
+#endif /* < 3.3.0 */
+		}
+
+		if (!conn->disable_time_checks &&
+		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+				   "not valid at this time",
+				   i + 1, num_certs);
+			gnutls_tls_fail_event(
+				conn, &certs[i], i, buf,
+				"Certificate is not valid at this time",
+				TLS_FAIL_EXPIRED);
+			gnutls_x509_crt_deinit(cert);
+			os_free(buf);
+			err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			goto out;
 		}
 
 		os_free(buf);
 
-		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
-		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
-			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
-				   "not valid at this time",
-				   i + 1, num_certs);
-			gnutls_x509_crt_deinit(cert);
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
-			return -1;
-		}
-
 		gnutls_x509_crt_deinit(cert);
 	}
 
+	if (conn->global->event_cb != NULL)
+		conn->global->event_cb(conn->global->cb_ctx,
+				       TLS_CERT_CHAIN_SUCCESS, NULL);
+
 	return 0;
+
+out:
+	conn->failed++;
+	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
+	return GNUTLS_E_CERTIFICATE_ERROR;
 }
 
 
@@ -979,6 +1260,8 @@
 
 	ret = gnutls_handshake(conn->session);
 	if (ret < 0) {
+		gnutls_alert_description_t alert;
+
 		switch (ret) {
 		case GNUTLS_E_AGAIN:
 			if (global->server && conn->established &&
@@ -989,10 +1272,20 @@
 			}
 			break;
 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
+			alert = gnutls_alert_get(conn->session);
 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
-				   __func__, gnutls_alert_get_name(
-					   gnutls_alert_get(conn->session)));
+				   __func__, gnutls_alert_get_name(alert));
 			conn->read_alerts++;
+			if (conn->global->event_cb != NULL) {
+				union tls_event_data ev;
+
+				os_memset(&ev, 0, sizeof(ev));
+				ev.alert.is_local = 0;
+				ev.alert.type = gnutls_alert_get_name(alert);
+				ev.alert.description = ev.alert.type;
+				conn->global->event_cb(conn->global->cb_ctx,
+						       TLS_ALERT, &ev);
+			}
 			/* continue */
 		default:
 			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
@@ -1001,18 +1294,21 @@
 		}
 	} else {
 		size_t size;
-		gnutls_alert_description_t err;
-
-		if (conn->verify_peer &&
-		    tls_connection_verify_peer(conn, &err)) {
-			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
-				   "failed validation");
-			conn->failed++;
-			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
-			goto out;
-		}
 
 		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010a
+		{
+			char *desc;
+
+			desc = gnutls_session_get_desc(conn->session);
+			if (desc) {
+				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
+				gnutls_free(desc);
+			}
+		}
+#endif /* GnuTLS 3.1.10 or newer */
+
 		conn->established = 1;
 		if (conn->push_buf == NULL) {
 			/* Need to return something to get final TLS ACK. */
@@ -1036,7 +1332,6 @@
 			*appl_data = gnutls_get_appl_data(conn);
 	}
 
-out:
 	out_data = conn->push_buf;
 	conn->push_buf = NULL;
 	return out_data;
@@ -1181,14 +1476,6 @@
 }
 
 
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	/* TODO */
-	return -1;
-}
-
-
 unsigned int tls_capabilities(void *tls_ctx)
 {
 	return 0;
@@ -1201,3 +1488,10 @@
 {
 	return -1;
 }
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
+			   GNUTLS_VERSION, gnutls_check_version(NULL));
+}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 6563ed2..afd4695 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -190,6 +190,36 @@
 	if (cred == NULL)
 		return -1;
 
+	if (params->subject_match) {
+		wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (params->altsubject_match) {
+		wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (params->suffix_match) {
+		wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (params->domain_match) {
+		wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (params->openssl_ciphers) {
+		wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
 	if (tlsv1_set_ca_cert(cred, params->ca_cert,
 			      params->ca_cert_blob, params->ca_cert_blob_len,
 			      params->ca_path)) {
@@ -323,25 +353,57 @@
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
+static int tls_get_keyblock_size(struct tls_connection *conn)
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       int skip_keyblock, u8 *out, size_t out_len)
+{
+	int ret = -1, skip = 0;
+	u8 *tmp_out = NULL;
+	u8 *_out = out;
+
+	if (skip_keyblock) {
+		skip = tls_get_keyblock_size(conn);
+		if (skip < 0)
+			return -1;
+		tmp_out = os_malloc(skip + out_len);
+		if (!tmp_out)
+			return -1;
+		_out = tmp_out;
+	}
+
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client) {
-		return tlsv1_client_prf(conn->client, label,
-					server_random_first,
-					out, out_len);
+		ret = tlsv1_client_prf(conn->client, label,
+				       server_random_first,
+				       _out, out_len);
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 	if (conn->server) {
-		return tlsv1_server_prf(conn->server, label,
-					server_random_first,
-					out, out_len);
+		ret = tlsv1_server_prf(conn->server, label,
+				       server_random_first,
+				       _out, out_len);
 	}
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
+	if (ret == 0 && skip_keyblock)
+		os_memcpy(out, _out + skip, out_len);
+	bin_clear_free(tmp_out, skip);
+
+	return ret;
 }
 
 
@@ -612,21 +674,6 @@
 }
 
 
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_get_keyblock_size(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_get_keyblock_size(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
 unsigned int tls_capabilities(void *tls_ctx)
 {
 	return 0;
@@ -652,3 +699,9 @@
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 }
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "internal");
+}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 1a1092a..1b1ba56 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -87,7 +87,7 @@
 
 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
+		       int skip_keyblock, u8 *out, size_t out_len)
 {
 	return -1;
 }
@@ -181,14 +181,13 @@
 }
 
 
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
 unsigned int tls_capabilities(void *tls_ctx)
 {
 	return 0;
 }
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "none");
+}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
deleted file mode 100644
index c53c192..0000000
--- a/src/crypto/tls_nss.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * SSL/TLS interface functions for NSS
- * Copyright (c) 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 <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prio.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nspr/prinit.h>
-#include <nspr/prerror.h>
-#include <nspr/prmem.h>
-#include <nss/nss.h>
-#include <nss/nssilckt.h>
-#include <nss/ssl.h>
-#include <nss/pk11func.h>
-#include <nss/secerr.h>
-
-#include "common.h"
-#include "tls.h"
-
-static int tls_nss_ref_count = 0;
-
-static PRDescIdentity nss_layer_id;
-
-
-struct tls_connection {
-	PRFileDesc *fd;
-
-	int established;
-	int verify_peer;
-	u8 *push_buf, *pull_buf, *pull_buf_offset;
-	size_t push_buf_len, pull_buf_len;
-};
-
-
-static PRStatus nss_io_close(PRFileDesc *fd)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O close");
-	return PR_SUCCESS;
-}
-
-
-static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
-			     PRInt32 iov_size, PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
-			   PRIntn flags, PRIntervalTime timeout)
-{
-	struct tls_connection *conn = (struct tls_connection *) fd->secret;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
-
-	if (conn->pull_buf == NULL) {
-		wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
-		return PR_FAILURE;
-	}
-
-	end = conn->pull_buf + conn->pull_buf_len;
-	if (end - conn->pull_buf_offset < amount)
-		amount = end - conn->pull_buf_offset;
-	os_memcpy(buf, conn->pull_buf_offset, amount);
-	conn->pull_buf_offset += amount;
-	if (conn->pull_buf_offset == end) {
-		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
-		os_free(conn->pull_buf);
-		conn->pull_buf = conn->pull_buf_offset = NULL;
-		conn->pull_buf_len = 0;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
-			   __func__,
-			   (unsigned long) (end - conn->pull_buf_offset));
-	}
-	return amount;
-}
-
-
-static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
-			   PRIntn flags, PRIntervalTime timeout)
-{
-	struct tls_connection *conn = (struct tls_connection *) fd->secret;
-	u8 *nbuf;
-
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
-
-	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
-	if (nbuf == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
-			   "data to be sent");
-		return PR_FAILURE;
-	}
-	os_memcpy(nbuf + conn->push_buf_len, buf, amount);
-	conn->push_buf = nbuf;
-	conn->push_buf_len += amount;
-
-	return amount;
-}
-
-
-static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
-			       PRIntn flags, PRNetAddr *addr,
-			       PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
-			     PRIntn flags, const PRNetAddr *addr,
-			     PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	return PR_FAILURE;
-}
-
-
-static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
-
-	/*
-	 * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
-	 * fake IPv4 address to work around this even though we are not really
-	 * using TCP.
-	 */
-	os_memset(addr, 0, sizeof(*addr));
-	addr->inet.family = PR_AF_INET;
-
-	return PR_SUCCESS;
-}
-
-
-static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
-				       PRSocketOptionData *data)
-{
-	switch (data->option) {
-	case PR_SockOpt_Nonblocking:
-		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
-		data->value.non_blocking = PR_TRUE;
-		return PR_SUCCESS;
-	default:
-		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
-			   data->option);
-		return PR_FAILURE;
-	}
-}
-
-
-static const PRIOMethods nss_io = {
-	PR_DESC_LAYERED,
-	nss_io_close,
-	nss_io_read,
-	nss_io_write,
-	NULL /* available */,
-	NULL /* available64 */,
-	NULL /* fsync */,
-	NULL /* fseek */,
-	NULL /* fseek64 */,
-	NULL /* fileinfo */,
-	NULL /* fileinfo64 */,
-	nss_io_writev,
-	NULL /* connect */,
-	NULL /* accept */,
-	NULL /* bind */,
-	NULL /* listen */,
-	NULL /* shutdown */,
-	nss_io_recv,
-	nss_io_send,
-	nss_io_recvfrom,
-	nss_io_sendto,
-	NULL /* poll */,
-	NULL /* acceptread */,
-	NULL /* transmitfile */,
-	NULL /* getsockname */,
-	nss_io_getpeername,
-	NULL /* reserved_fn_6 */,
-	NULL /* reserved_fn_5 */,
-	nss_io_getsocketoption,
-	NULL /* setsocketoption */,
-	NULL /* sendfile */,
-	NULL /* connectcontinue */,
-	NULL /* reserved_fn_3 */,
-	NULL /* reserved_fn_2 */,
-	NULL /* reserved_fn_1 */,
-	NULL /* reserved_fn_0 */
-};
-
-
-static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
-{
-	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
-	return NULL;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	char *dir;
-
-	tls_nss_ref_count++;
-	if (tls_nss_ref_count > 1)
-		return (void *) 1;
-
-	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
-
-	nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
-
-	PK11_SetPasswordFunc(nss_password_cb);
-
-	dir = getenv("SSL_DIR");
-	if (dir) {
-		if (NSS_Init(dir) != SECSuccess) {
-			wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
-				   "failed", dir);
-			return NULL;
-		}
-	} else {
-		if (NSS_NoDB_Init(NULL) != SECSuccess) {
-			wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
-				   "failed");
-			return NULL;
-		}
-	}
-
-	if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
-	    SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
-		return NULL;
-	}
-
-	if (NSS_SetDomesticPolicy() != SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
-		return NULL;
-	}
-
-	return (void *) 1;
-}
-
-void tls_deinit(void *ssl_ctx)
-{
-	tls_nss_ref_count--;
-	if (tls_nss_ref_count == 0) {
-		if (NSS_Shutdown() != SECSuccess)
-			wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
-	}
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
-	return 0;
-}
-
-
-static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
-{
-	struct tls_connection *conn = arg;
-	SECStatus res = SECSuccess;
-	PRErrorCode err;
-	CERTCertificate *cert;
-	char *subject, *issuer;
-
-	err = PR_GetError();
-	if (IS_SEC_ERROR(err))
-		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
-			   "%d)", err - SEC_ERROR_BASE);
-	else
-		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
-			   err);
-	cert = SSL_PeerCertificate(fd);
-	subject = CERT_NameToAscii(&cert->subject);
-	issuer = CERT_NameToAscii(&cert->issuer);
-	wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
-		   subject, issuer);
-	CERT_DestroyCertificate(cert);
-	PR_Free(subject);
-	PR_Free(issuer);
-	if (conn->verify_peer)
-		res = SECFailure;
-
-	return res;
-}
-
-
-static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
-{
-	struct tls_connection *conn = client_data;
-	wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
-	conn->established = 1;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
-	struct tls_connection *conn;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-	conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
-	if (conn->fd == NULL) {
-		os_free(conn);
-		return NULL;
-	}
-	conn->fd->secret = (void *) conn;
-
-	conn->fd = SSL_ImportFD(NULL, conn->fd);
-	if (conn->fd == NULL) {
-		os_free(conn);
-		return NULL;
-	}
-
-	if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
-	    SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
-	    SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
-	    SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
-	    SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
-	    SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: Failed to set options");
-		PR_Close(conn->fd);
-		os_free(conn);
-		return NULL;
-	}
-
-	SSL_ResetHandshake(conn->fd, PR_FALSE);
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
-	PR_Close(conn->fd);
-	os_free(conn->push_buf);
-	os_free(conn->pull_buf);
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
-	return conn->established;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
-	return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
-	return -1;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	conn->verify_peer = verify_peer;
-	return 0;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	/* NSS does not export master secret or client/server random. */
-	return -1;
-}
-
-
-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 (conn == NULL || server_random_first) {
-		wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
-			   "(server_random_first=%d)",
-			   server_random_first);
-		return -1;
-	}
-
-	if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
-	    SECSuccess) {
-		wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
-			   "(label='%s' out_len=%d", label, (int) out_len);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	struct wpabuf *out_data;
-
-	wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
-		   in_data ? (unsigned int) wpabuf_len(in_data) : 0);
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	if (in_data && wpabuf_len(in_data) > 0) {
-		if (conn->pull_buf) {
-			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-				   "pull_buf", __func__,
-				   (unsigned long) conn->pull_buf_len);
-			os_free(conn->pull_buf);
-		}
-		conn->pull_buf = os_malloc(wpabuf_len(in_data));
-		if (conn->pull_buf == NULL)
-			return NULL;
-		os_memcpy(conn->pull_buf, wpabuf_head(in_data),
-			  wpabuf_len(in_data));
-		conn->pull_buf_offset = conn->pull_buf;
-		conn->pull_buf_len = wpabuf_len(in_data);
-	}
-
-	SSL_ForceHandshake(conn->fd);
-
-	if (conn->established && conn->push_buf == NULL) {
-		/* Need to return something to get final TLS ACK. */
-		conn->push_buf = os_malloc(1);
-	}
-
-	if (conn->push_buf == NULL)
-		return NULL;
-	out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
-	if (out_data == NULL)
-		os_free(conn->push_buf);
-	conn->push_buf = NULL;
-	conn->push_buf_len = 0;
-	return out_data;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	PRInt32 res;
-	struct wpabuf *buf;
-
-	wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
-		   (int) wpabuf_len(in_data));
-	res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
-		      0);
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "NSS: Encryption failed");
-		return NULL;
-	}
-	if (conn->push_buf == NULL)
-		return NULL;
-	buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
-	if (buf == NULL)
-		os_free(conn->push_buf);
-	conn->push_buf = NULL;
-	conn->push_buf_len = 0;
-	return buf;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	PRInt32 res;
-	struct wpabuf *out;
-
-	wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
-		   (int) wpabuf_len(in_data));
-	if (conn->pull_buf) {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-			   "pull_buf", __func__,
-			   (unsigned long) conn->pull_buf_len);
-		os_free(conn->pull_buf);
-	}
-	conn->pull_buf = os_malloc(wpabuf_len(in_data));
-	if (conn->pull_buf == NULL)
-		return NULL;
-	os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
-	conn->pull_buf_offset = conn->pull_buf;
-	conn->pull_buf_len = wpabuf_len(in_data);
-
-	/*
-	 * Even though we try to disable TLS compression, it is possible that
-	 * this cannot be done with all TLS libraries. Add extra buffer space
-	 * to handle the possibility of the decrypted data being longer than
-	 * input data.
-	 */
-	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-	if (out == NULL)
-		return NULL;
-
-	res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
-	wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
-	if (res < 0) {
-		wpabuf_free(out);
-		return NULL;
-	}
-	wpabuf_put(out, res);
-
-	return out;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
-				    struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
-					 struct tls_connection *conn,
-					 tls_session_ticket_cb cb,
-					 void *ctx)
-{
-	return -1;
-}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index c72134a..d3e9eb9 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -26,14 +26,9 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "sha1.h"
 #include "tls.h"
 
-#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-#define OPENSSL_d2i_TYPE const unsigned char **
-#else
-#define OPENSSL_d2i_TYPE unsigned char **
-#endif
-
 #if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
 #define OPENSSL_SUPPORTS_CTX_APP_DATA
 #endif
@@ -90,13 +85,14 @@
 
 struct tls_connection {
 	struct tls_context *context;
+	SSL_CTX *ssl_ctx;
 	SSL *ssl;
 	BIO *ssl_in, *ssl_out;
 #ifndef OPENSSL_NO_ENGINE
 	ENGINE *engine;        /* functional reference to the engine */
 	EVP_PKEY *private_key; /* the private key if using engine */
 #endif /* OPENSSL_NO_ENGINE */
-	char *subject_match, *altsubject_match, *suffix_match;
+	char *subject_match, *altsubject_match, *suffix_match, *domain_match;
 	int read_alerts, write_alerts, failed;
 
 	tls_session_ticket_cb session_ticket_cb;
@@ -400,7 +396,8 @@
 		goto err;
 	}
 
-	cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+	cert = d2i_X509(NULL,
+			(const unsigned char **) &priv->cert->pbCertEncoded,
 			priv->cert->cbCertEncoded);
 	if (cert == NULL) {
 		wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
@@ -500,7 +497,8 @@
 	}
 
 	while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
-		cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+		cert = d2i_X509(NULL,
+				(const unsigned char **) &ctx->pbCertEncoded,
 				ctx->cbCertEncoded);
 		if (cert == NULL) {
 			wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
@@ -774,7 +772,7 @@
 #endif /* CONFIG_FIPS */
 		SSL_load_error_strings();
 		SSL_library_init();
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifndef OPENSSL_NO_SHA256
 		EVP_add_digest(EVP_sha256());
 #endif /* OPENSSL_NO_SHA256 */
 		/* TODO: if /dev/urandom is available, PRNG is seeded
@@ -1045,6 +1043,7 @@
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 		return NULL;
+	conn->ssl_ctx = ssl_ctx;
 	conn->ssl = SSL_new(ssl);
 	if (conn->ssl == NULL) {
 		tls_show_errors(MSG_INFO, __func__,
@@ -1098,6 +1097,7 @@
 	os_free(conn->subject_match);
 	os_free(conn->altsubject_match);
 	os_free(conn->suffix_match);
+	os_free(conn->domain_match);
 	os_free(conn->session_ticket);
 	os_free(conn);
 }
@@ -1190,7 +1190,8 @@
 
 
 #ifndef CONFIG_NATIVE_WINDOWS
-static int domain_suffix_match(const u8 *val, size_t len, const char *match)
+static int domain_suffix_match(const u8 *val, size_t len, const char *match,
+			       int full)
 {
 	size_t i, match_len;
 
@@ -1203,7 +1204,7 @@
 	}
 
 	match_len = os_strlen(match);
-	if (match_len > len)
+	if (match_len > len || (full && match_len != len))
 		return 0;
 
 	if (os_strncasecmp((const char *) val + len - match_len, match,
@@ -1222,7 +1223,7 @@
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 
-static int tls_match_suffix(X509 *cert, const char *match)
+static int tls_match_suffix(X509 *cert, const char *match, int full)
 {
 #ifdef CONFIG_NATIVE_WINDOWS
 	/* wincrypt.h has conflicting X509_NAME definition */
@@ -1235,7 +1236,8 @@
 	int dns_name = 0;
 	X509_NAME *name;
 
-	wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+		   full ? "": "suffix ", match);
 
 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 
@@ -1248,8 +1250,10 @@
 				  gen->d.dNSName->data,
 				  gen->d.dNSName->length);
 		if (domain_suffix_match(gen->d.dNSName->data,
-					gen->d.dNSName->length, match) == 1) {
-			wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found");
+					gen->d.dNSName->length, match, full) ==
+		    1) {
+			wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+				   full ? "Match" : "Suffix match");
 			return 1;
 		}
 	}
@@ -1276,13 +1280,16 @@
 			continue;
 		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
 				  cn->data, cn->length);
-		if (domain_suffix_match(cn->data, cn->length, match) == 1) {
-			wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found");
+		if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+		{
+			wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+				   full ? "Match" : "Suffix match");
 			return 1;
 		}
 	}
 
-	wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+	wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+		   full ? "": "suffix ");
 	return 0;
 #endif /* CONFIG_NATIVE_WINDOWS */
 }
@@ -1377,6 +1384,11 @@
 	struct wpabuf *cert = NULL;
 	union tls_event_data ev;
 	struct tls_context *context = conn->context;
+	char *altsubject[TLS_MAX_ALT_SUBJECT];
+	int alt, num_altsubject = 0;
+	GENERAL_NAME *gen;
+	void *ext;
+	stack_index_t i;
 #ifdef CONFIG_SHA256
 	u8 hash[32];
 #endif /* CONFIG_SHA256 */
@@ -1403,8 +1415,52 @@
 #endif /* CONFIG_SHA256 */
 	ev.peer_cert.depth = depth;
 	ev.peer_cert.subject = subject;
+
+	ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		char *pos;
+
+		if (num_altsubject == TLS_MAX_ALT_SUBJECT)
+			break;
+		gen = sk_GENERAL_NAME_value(ext, i);
+		if (gen->type != GEN_EMAIL &&
+		    gen->type != GEN_DNS &&
+		    gen->type != GEN_URI)
+			continue;
+
+		pos = os_malloc(10 + gen->d.ia5->length + 1);
+		if (pos == NULL)
+			break;
+		altsubject[num_altsubject++] = pos;
+
+		switch (gen->type) {
+		case GEN_EMAIL:
+			os_memcpy(pos, "EMAIL:", 6);
+			pos += 6;
+			break;
+		case GEN_DNS:
+			os_memcpy(pos, "DNS:", 4);
+			pos += 4;
+			break;
+		case GEN_URI:
+			os_memcpy(pos, "URI:", 4);
+			pos += 4;
+			break;
+		}
+
+		os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
+		pos += gen->d.ia5->length;
+		*pos = '\0';
+	}
+
+	for (alt = 0; alt < num_altsubject; alt++)
+		ev.peer_cert.altsubject[alt] = altsubject[alt];
+	ev.peer_cert.num_altsubject = num_altsubject;
+
 	context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
 	wpabuf_free(cert);
+	for (alt = 0; alt < num_altsubject; alt++)
+		os_free(altsubject[alt]);
 }
 
 
@@ -1416,7 +1472,7 @@
 	SSL *ssl;
 	struct tls_connection *conn;
 	struct tls_context *context;
-	char *match, *altmatch, *suffix_match;
+	char *match, *altmatch, *suffix_match, *domain_match;
 	const char *err_str;
 
 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1444,6 +1500,7 @@
 	match = conn->subject_match;
 	altmatch = conn->altsubject_match;
 	suffix_match = conn->suffix_match;
+	domain_match = conn->domain_match;
 
 	if (!preverify_ok && !conn->ca_cert_verify)
 		preverify_ok = 1;
@@ -1460,7 +1517,11 @@
 	err_str = X509_verify_cert_error_string(err);
 
 #ifdef CONFIG_SHA256
-	if (preverify_ok && depth == 0 && conn->server_cert_only) {
+	/*
+	 * Do not require preverify_ok so we can explicity allow otherwise
+	 * invalid pinned server certificates.
+	 */
+	if (depth == 0 && conn->server_cert_only) {
 		struct wpabuf *cert;
 		cert = get_x509_cert(err_cert);
 		if (!cert) {
@@ -1478,6 +1539,14 @@
 				err_str = "Server certificate mismatch";
 				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
 				preverify_ok = 0;
+			} else if (!preverify_ok) {
+				/*
+				 * Certificate matches pinned certificate, allow
+				 * regardless of other problems.
+				 */
+				wpa_printf(MSG_DEBUG,
+					   "OpenSSL: Ignore validation issues for a pinned server certificate");
+				preverify_ok = 1;
 			}
 			wpabuf_free(cert);
 		}
@@ -1513,13 +1582,21 @@
 				       "AltSubject mismatch",
 				       TLS_FAIL_ALTSUBJECT_MISMATCH);
 	} else if (depth == 0 && suffix_match &&
-		   !tls_match_suffix(err_cert, suffix_match)) {
+		   !tls_match_suffix(err_cert, suffix_match, 0)) {
 		wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
 			   suffix_match);
 		preverify_ok = 0;
 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 				       "Domain suffix mismatch",
 				       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+	} else if (depth == 0 && domain_match &&
+		   !tls_match_suffix(err_cert, domain_match, 1)) {
+		wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+			   domain_match);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Domain mismatch",
+				       TLS_FAIL_DOMAIN_MISMATCH);
 	} else
 		openssl_tls_cert_event(conn, err_cert, depth, buf);
 
@@ -1547,7 +1624,7 @@
 	X509_LOOKUP *lookup;
 	int ret = 0;
 
-	lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+	lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
 				       X509_LOOKUP_file());
 	if (lookup == NULL) {
 		tls_show_errors(MSG_WARNING, __func__,
@@ -1578,18 +1655,19 @@
 				  size_t ca_cert_blob_len, const char *ca_path)
 {
 	SSL_CTX *ssl_ctx = _ssl_ctx;
+	X509_STORE *store;
 
 	/*
 	 * Remove previously configured trusted CA certificates before adding
 	 * new ones.
 	 */
-	X509_STORE_free(ssl_ctx->cert_store);
-	ssl_ctx->cert_store = X509_STORE_new();
-	if (ssl_ctx->cert_store == NULL) {
+	store = X509_STORE_new();
+	if (store == NULL) {
 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 			   "certificate store", __func__);
 		return -1;
 	}
+	SSL_CTX_set_cert_store(ssl_ctx, store);
 
 	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 	conn->ca_cert_verify = 1;
@@ -1633,7 +1711,8 @@
 	}
 
 	if (ca_cert_blob) {
-		X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+		X509 *cert = d2i_X509(NULL,
+				      (const unsigned char **) &ca_cert_blob,
 				      ca_cert_blob_len);
 		if (cert == NULL) {
 			tls_show_errors(MSG_WARNING, __func__,
@@ -1641,7 +1720,8 @@
 			return -1;
 		}
 
-		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+		if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+					 cert)) {
 			unsigned long err = ERR_peek_error();
 			tls_show_errors(MSG_WARNING, __func__,
 					"Failed to add ca_cert_blob to "
@@ -1783,7 +1863,8 @@
 static int tls_connection_set_subject_match(struct tls_connection *conn,
 					    const char *subject_match,
 					    const char *altsubject_match,
-					    const char *suffix_match)
+					    const char *suffix_match,
+					    const char *domain_match)
 {
 	os_free(conn->subject_match);
 	conn->subject_match = NULL;
@@ -1809,6 +1890,14 @@
 			return -1;
 	}
 
+	os_free(conn->domain_match);
+	conn->domain_match = NULL;
+	if (domain_match) {
+		conn->domain_match = os_strdup(domain_match);
+		if (conn->domain_match == NULL)
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -2063,7 +2152,7 @@
 #ifdef PKCS12_FUNCS
 	PKCS12 *p12;
 
-	p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+	p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
 	if (p12 == NULL) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to use PKCS#12 blob");
@@ -2144,20 +2233,21 @@
 #ifndef OPENSSL_NO_ENGINE
 	X509 *cert;
 	SSL_CTX *ssl_ctx = _ssl_ctx;
+	X509_STORE *store;
 
 	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
 		return -1;
 
 	/* start off the same as tls_connection_ca_cert */
-	X509_STORE_free(ssl_ctx->cert_store);
-	ssl_ctx->cert_store = X509_STORE_new();
-	if (ssl_ctx->cert_store == NULL) {
+	store = X509_STORE_new();
+	if (store == NULL) {
 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 			   "certificate store", __func__);
 		X509_free(cert);
 		return -1;
 	}
-	if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+	SSL_CTX_set_cert_store(ssl_ctx, store);
+	if (!X509_STORE_add_cert(store, cert)) {
 		unsigned long err = ERR_peek_error();
 		tls_show_errors(MSG_WARNING, __func__,
 				"Failed to add CA certificate from engine "
@@ -2543,8 +2633,6 @@
 		return -1;
 
 	os_memset(keys, 0, sizeof(*keys));
-	keys->master_key = ssl->session->master_key;
-	keys->master_key_len = ssl->session->master_key_length;
 	keys->client_random = ssl->s3->client_random;
 	keys->client_random_len = SSL3_RANDOM_SIZE;
 	keys->server_random = ssl->s3->server_random;
@@ -2555,16 +2643,121 @@
 }
 
 
+static int openssl_get_keyblock_size(SSL *ssl)
+{
+	const EVP_CIPHER *c;
+	const EVP_MD *h;
+	int md_size;
+
+	if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
+	    ssl->read_hash == NULL)
+		return -1;
+
+	c = ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+	h = EVP_MD_CTX_md(ssl->read_hash);
+#else
+	h = conn->ssl->read_hash;
+#endif
+	if (h)
+		md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+	else if (ssl->s3)
+		md_size = 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) +
+		    md_size +
+		    EVP_CIPHER_iv_length(c));
+}
+
+
+static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
+			   const char *label, int server_random_first,
+			   int skip_keyblock, u8 *out, size_t out_len)
+{
+#ifdef CONFIG_FIPS
+	wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+		   "mode");
+	return -1;
+#else /* CONFIG_FIPS */
+	SSL *ssl;
+	u8 *rnd;
+	int ret = -1;
+	int skip = 0;
+	u8 *tmp_out = NULL;
+	u8 *_out = out;
+
+	/*
+	 * TLS library did not support key generation, so get the needed TLS
+	 * session parameters and use an internal implementation of TLS PRF to
+	 * derive the key.
+	 */
+
+	if (conn == NULL)
+		return -1;
+	ssl = conn->ssl;
+	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
+	    ssl->session->master_key_length <= 0)
+		return -1;
+
+	if (skip_keyblock) {
+		skip = openssl_get_keyblock_size(ssl);
+		if (skip < 0)
+			return -1;
+		tmp_out = os_malloc(skip + out_len);
+		if (!tmp_out)
+			return -1;
+		_out = tmp_out;
+	}
+
+	rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
+	if (rnd == NULL)
+		return -1;
+	if (server_random_first) {
+		os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+		os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
+			SSL3_RANDOM_SIZE);
+	} else {
+		os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+		os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
+			SSL3_RANDOM_SIZE);
+	}
+
+	/* TODO: TLSv1.2 may need another PRF. This could use something closer
+	 * to SSL_export_keying_material() design. */
+	if (tls_prf_sha1_md5(ssl->session->master_key,
+			     ssl->session->master_key_length,
+			     label, rnd, 2 * SSL3_RANDOM_SIZE,
+			     _out, skip + out_len) == 0)
+		ret = 0;
+	os_free(rnd);
+	if (ret == 0 && skip_keyblock)
+		os_memcpy(out, _out + skip, out_len);
+	bin_clear_free(tmp_out, skip);
+
+	return ret;
+#endif /* CONFIG_FIPS */
+}
+
+
 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
+		       int skip_keyblock, u8 *out, size_t out_len)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
 	SSL *ssl;
 	if (conn == NULL)
 		return -1;
-	if (server_random_first)
-		return -1;
+	if (server_random_first || skip_keyblock)
+		return openssl_tls_prf(tls_ctx, conn, label,
+				       server_random_first, skip_keyblock,
+				       out, out_len);
 	ssl = conn->ssl;
 	if (SSL_export_keying_material(ssl, out, out_len, label,
 				       os_strlen(label), NULL, 0, 0) == 1) {
@@ -2572,7 +2765,8 @@
 		return 0;
 	}
 #endif
-	return -1;
+	return openssl_tls_prf(tls_ctx, conn, label, server_random_first,
+			       skip_keyblock, out, out_len);
 }
 
 
@@ -2825,7 +3019,11 @@
 
 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+	return conn ? SSL_cache_hit(conn->ssl) : 0;
+#else
 	return conn ? conn->ssl->hit : 0;
+#endif
 }
 
 
@@ -3066,13 +3264,13 @@
 		return 0;
 	}
 
-	store = SSL_CTX_get_cert_store(s->ctx);
+	store = SSL_CTX_get_cert_store(conn->ssl_ctx);
 	if (conn->peer_issuer) {
 		debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
 
 		if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
 			tls_show_errors(MSG_INFO, __func__,
-					"OpenSSL: Could not add issuer to certificate store\n");
+					"OpenSSL: Could not add issuer to certificate store");
 		}
 		certs = sk_X509_new_null();
 		if (certs) {
@@ -3081,17 +3279,17 @@
 			if (cert && !sk_X509_push(certs, cert)) {
 				tls_show_errors(
 					MSG_INFO, __func__,
-					"OpenSSL: Could not add issuer to OCSP responder trust store\n");
+					"OpenSSL: Could not add issuer to OCSP responder trust store");
 				X509_free(cert);
 				sk_X509_free(certs);
 				certs = NULL;
 			}
-			if (conn->peer_issuer_issuer) {
+			if (certs && conn->peer_issuer_issuer) {
 				cert = X509_dup(conn->peer_issuer_issuer);
 				if (cert && !sk_X509_push(certs, cert)) {
 					tls_show_errors(
 						MSG_INFO, __func__,
-						"OpenSSL: Could not add issuer to OCSP responder trust store\n");
+						"OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
 					X509_free(cert);
 				}
 			}
@@ -3273,7 +3471,8 @@
 	if (tls_connection_set_subject_match(conn,
 					     params->subject_match,
 					     params->altsubject_match,
-					     params->suffix_match))
+					     params->suffix_match,
+					     params->domain_match))
 		return -1;
 
 	if (engine_id && ca_cert_id) {
@@ -3420,43 +3619,6 @@
 }
 
 
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	const EVP_CIPHER *c;
-	const EVP_MD *h;
-	int md_size;
-
-	if (conn == NULL || conn->ssl == NULL ||
-	    conn->ssl->enc_read_ctx == NULL ||
-	    conn->ssl->enc_read_ctx->cipher == NULL ||
-	    conn->ssl->read_hash == NULL)
-		return -1;
-
-	c = conn->ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-	h = EVP_MD_CTX_md(conn->ssl->read_hash);
-#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) +
-		    md_size +
-		    EVP_CIPHER_iv_length(c));
-}
-
-
 unsigned int tls_capabilities(void *tls_ctx)
 {
 	return 0;
@@ -3554,3 +3716,11 @@
 	return -1;
 #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 }
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+			   OPENSSL_VERSION_TEXT,
+			   SSLeay_version(SSLEAY_VERSION));
+}
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
deleted file mode 100644
index 2c2daa8..0000000
--- a/src/crypto/tls_schannel.c
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/*
- * FIX: Go through all SSPI functions and verify what needs to be freed
- * FIX: session resumption
- * TODO: add support for server cert chain validation
- * TODO: add support for CA cert validation
- * TODO: add support for EAP-TLS (client cert/key conf)
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-#include <schannel.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <sspi.h>
-
-#include "common.h"
-#include "tls.h"
-
-
-struct tls_global {
-	HMODULE hsecurity;
-	PSecurityFunctionTable sspi;
-	HCERTSTORE my_cert_store;
-};
-
-struct tls_connection {
-	int established, start;
-	int failed, read_alerts, write_alerts;
-
-	SCHANNEL_CRED schannel_cred;
-	CredHandle creds;
-	CtxtHandle context;
-
-	u8 eap_tls_prf[128];
-	int eap_tls_prf_set;
-};
-
-
-static int schannel_load_lib(struct tls_global *global)
-{
-	INIT_SECURITY_INTERFACE pInitSecurityInterface;
-
-	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
-	if (global->hsecurity == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		return -1;
-	}
-
-	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
-		global->hsecurity, "InitSecurityInterfaceA");
-	if (pInitSecurityInterface == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not find "
-			   "InitSecurityInterfaceA from Secur32.dll",
-			   __func__);
-		FreeLibrary(global->hsecurity);
-		global->hsecurity = NULL;
-		return -1;
-	}
-
-	global->sspi = pInitSecurityInterface();
-	if (global->sspi == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not read security "
-			   "interface - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		FreeLibrary(global->hsecurity);
-		global->hsecurity = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	struct tls_global *global;
-
-	global = os_zalloc(sizeof(*global));
-	if (global == NULL)
-		return NULL;
-	if (schannel_load_lib(global)) {
-		os_free(global);
-		return NULL;
-	}
-	return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
-	struct tls_global *global = ssl_ctx;
-
-	if (global->my_cert_store)
-		CertCloseStore(global->my_cert_store, 0);
-	FreeLibrary(global->hsecurity);
-	os_free(global);
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
-	return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
-	struct tls_connection *conn;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-	conn->start = 1;
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return;
-
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
-	return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
-	struct tls_global *global = ssl_ctx;
-	if (conn == NULL)
-		return -1;
-
-	conn->eap_tls_prf_set = 0;
-	conn->established = conn->failed = 0;
-	conn->read_alerts = conn->write_alerts = 0;
-	global->sspi->DeleteSecurityContext(&conn->context);
-	/* FIX: what else needs to be reseted? */
-
-	return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
-	return -1;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	return -1;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	/* Schannel does not export master secret or client/server random. */
-	return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-	/*
-	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
-	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
-	 * EAP-TTLS cannot use this, though, since they are using different
-	 * labels. The only option could be to implement TLSv1 completely here
-	 * and just use Schannel or CryptoAPI for low-level crypto
-	 * functionality..
-	 */
-
-	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
-	    os_strcmp(label, "client EAP encryption") != 0 ||
-	    out_len > sizeof(conn->eap_tls_prf))
-		return -1;
-
-	os_memcpy(out, conn->eap_tls_prf, out_len);
-
-	return 0;
-}
-
-
-static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
-					       struct tls_connection *conn)
-{
-	DWORD sspi_flags, sspi_flags_out;
-	SecBufferDesc outbuf;
-	SecBuffer outbufs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-
-	sspi_flags = ISC_REQ_REPLAY_DETECT |
-		ISC_REQ_CONFIDENTIALITY |
-		ISC_RET_EXTENDED_ERROR |
-		ISC_REQ_ALLOCATE_MEMORY |
-		ISC_REQ_MANUAL_CRED_VALIDATION;
-
-	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
-
-	outbufs[0].pvBuffer = NULL;
-	outbufs[0].BufferType = SECBUFFER_TOKEN;
-	outbufs[0].cbBuffer = 0;
-
-	outbuf.cBuffers = 1;
-	outbuf.pBuffers = outbufs;
-	outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
-	status = global->sspi->InitializeSecurityContextW(
-		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->InitializeSecurityContextA(
-		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-	if (status != SEC_I_CONTINUE_NEEDED) {
-		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
-			   "failed - 0x%x",
-			   __func__, (unsigned int) status);
-		return NULL;
-	}
-
-	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
-		struct wpabuf *buf;
-		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
-			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
-		conn->start = 0;
-		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
-					outbufs[0].cbBuffer);
-		if (buf == NULL)
-			return NULL;
-		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
-		return buf;
-	}
-
-	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
-
-	return NULL;
-}
-
-
-#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
-#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
-
-typedef struct _SecPkgContext_EapKeyBlock {
-	BYTE rgbKeys[128];
-	BYTE rgbIVs[64];
-} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
-#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
-
-static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
-{
-	SECURITY_STATUS status;
-	SecPkgContext_EapKeyBlock kb;
-
-	/* Note: Windows NT and Windows Me/98/95 do not support getting
-	 * EapKeyBlock */
-
-	status = global->sspi->QueryContextAttributes(
-		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
-			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
-			   __func__, (int) status);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
-			kb.rgbKeys, sizeof(kb.rgbKeys));
-	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
-			kb.rgbIVs, sizeof(kb.rgbIVs));
-
-	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
-	conn->eap_tls_prf_set = 1;
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	struct tls_global *global = tls_ctx;
-	DWORD sspi_flags, sspi_flags_out;
-	SecBufferDesc inbuf, outbuf;
-	SecBuffer inbufs[2], outbufs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-	struct wpabuf *out_buf = NULL;
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	if (conn->start)
-		return tls_conn_hs_clienthello(global, conn);
-
-	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
-		   (int) wpabuf_len(in_data));
-
-	sspi_flags = ISC_REQ_REPLAY_DETECT |
-		ISC_REQ_CONFIDENTIALITY |
-		ISC_RET_EXTENDED_ERROR |
-		ISC_REQ_ALLOCATE_MEMORY |
-		ISC_REQ_MANUAL_CRED_VALIDATION;
-
-	/* Input buffer for Schannel */
-	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
-	inbufs[0].cbBuffer = wpabuf_len(in_data);
-	inbufs[0].BufferType = SECBUFFER_TOKEN;
-
-	/* Place for leftover data from Schannel */
-	inbufs[1].pvBuffer = NULL;
-	inbufs[1].cbBuffer = 0;
-	inbufs[1].BufferType = SECBUFFER_EMPTY;
-
-	inbuf.cBuffers = 2;
-	inbuf.pBuffers = inbufs;
-	inbuf.ulVersion = SECBUFFER_VERSION;
-
-	/* Output buffer for Schannel */
-	outbufs[0].pvBuffer = NULL;
-	outbufs[0].cbBuffer = 0;
-	outbufs[0].BufferType = SECBUFFER_TOKEN;
-
-	outbuf.cBuffers = 1;
-	outbuf.pBuffers = outbufs;
-	outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
-	status = global->sspi->InitializeSecurityContextW(
-		&conn->creds, &conn->context, NULL, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->InitializeSecurityContextA(
-		&conn->creds, &conn->context, NULL, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-
-	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
-		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
-		   "intype[1]=%d outlen[0]=%d",
-		   (int) status, (int) inbufs[0].cbBuffer,
-		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
-		   (int) inbufs[1].BufferType,
-		   (int) outbufs[0].cbBuffer);
-	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
-	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
-		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
-			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
-				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
-			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
-						    outbufs[0].cbBuffer);
-			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
-			outbufs[0].pvBuffer = NULL;
-			if (out_buf == NULL)
-				return NULL;
-		}
-	}
-
-	switch (status) {
-	case SEC_E_INCOMPLETE_MESSAGE:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
-		break;
-	case SEC_I_CONTINUE_NEEDED:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
-		break;
-	case SEC_E_OK:
-		/* TODO: verify server certificate chain */
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
-			   "completed successfully");
-		conn->established = 1;
-		tls_get_eap(global, conn);
-
-		/* Need to return something to get final TLS ACK. */
-		if (out_buf == NULL)
-			out_buf = wpabuf_alloc(0);
-
-		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
-			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
-				    "application data",
-				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
-			if (appl_data) {
-				*appl_data = wpabuf_alloc_copy(
-					outbufs[1].pvBuffer,
-					outbufs[1].cbBuffer);
-			}
-			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
-			inbufs[1].pvBuffer = NULL;
-		}
-		break;
-	case SEC_I_INCOMPLETE_CREDENTIALS:
-		wpa_printf(MSG_DEBUG,
-			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
-		break;
-	case SEC_E_WRONG_PRINCIPAL:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
-		break;
-	case SEC_E_INTERNAL_ERROR:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
-		break;
-	}
-
-	if (FAILED(status)) {
-		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
-			   "(out_buf=%p)", out_buf);
-		conn->failed++;
-		global->sspi->DeleteSecurityContext(&conn->context);
-		return out_buf;
-	}
-
-	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
-		/* TODO: Can this happen? What to do with this data? */
-		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
-			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
-		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
-		inbufs[1].pvBuffer = NULL;
-	}
-
-	return out_buf;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	struct tls_global *global = tls_ctx;
-	SECURITY_STATUS status;
-	SecBufferDesc buf;
-	SecBuffer bufs[4];
-	SecPkgContext_StreamSizes sizes;
-	int i;
-	struct wpabuf *out;
-
-	status = global->sspi->QueryContextAttributes(&conn->context,
-						      SECPKG_ATTR_STREAM_SIZES,
-						      &sizes);
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
-			   __func__);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
-		   __func__,
-		   (unsigned int) sizes.cbHeader,
-		   (unsigned int) sizes.cbTrailer);
-
-	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
-			   sizes.cbTrailer);
-
-	os_memset(&bufs, 0, sizeof(bufs));
-	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
-	bufs[0].cbBuffer = sizes.cbHeader;
-	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
-
-	bufs[1].pvBuffer = wpabuf_put(out, 0);
-	wpabuf_put_buf(out, in_data);
-	bufs[1].cbBuffer = wpabuf_len(in_data);
-	bufs[1].BufferType = SECBUFFER_DATA;
-
-	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
-	bufs[2].cbBuffer = sizes.cbTrailer;
-	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-
-	buf.ulVersion = SECBUFFER_VERSION;
-	buf.cBuffers = 3;
-	buf.pBuffers = bufs;
-
-	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
-
-	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
-		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
-		   "len[2]=%d type[2]=%d",
-		   (int) status,
-		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
-		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
-		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
-	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
-		   "out_data=%p bufs %p %p %p",
-		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
-		   bufs[2].pvBuffer);
-
-	for (i = 0; i < 3; i++) {
-		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
-		{
-			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
-				    bufs[i].pvBuffer, bufs[i].cbBuffer);
-		}
-	}
-
-	if (status == SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
-		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
-				    "from EncryptMessage", out);
-		return out;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
-		   __func__, (int) status);
-	wpabuf_free(out);
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	struct tls_global *global = tls_ctx;
-	SECURITY_STATUS status;
-	SecBufferDesc buf;
-	SecBuffer bufs[4];
-	int i;
-	struct wpabuf *out, *tmp;
-
-	wpa_hexdump_buf(MSG_MSGDUMP,
-			"Schannel: Encrypted data to DecryptMessage", in_data);
-	os_memset(&bufs, 0, sizeof(bufs));
-	tmp = wpabuf_dup(in_data);
-	if (tmp == NULL)
-		return NULL;
-	bufs[0].pvBuffer = wpabuf_mhead(tmp);
-	bufs[0].cbBuffer = wpabuf_len(in_data);
-	bufs[0].BufferType = SECBUFFER_DATA;
-
-	bufs[1].BufferType = SECBUFFER_EMPTY;
-	bufs[2].BufferType = SECBUFFER_EMPTY;
-	bufs[3].BufferType = SECBUFFER_EMPTY;
-
-	buf.ulVersion = SECBUFFER_VERSION;
-	buf.cBuffers = 4;
-	buf.pBuffers = bufs;
-
-	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
-						    NULL);
-	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
-		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
-		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
-		   (int) status,
-		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
-		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
-		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
-		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
-	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
-		   "out_data=%p bufs %p %p %p %p",
-		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
-		   bufs[2].pvBuffer, bufs[3].pvBuffer);
-
-	switch (status) {
-	case SEC_E_INCOMPLETE_MESSAGE:
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
-			   __func__);
-		break;
-	case SEC_E_OK:
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
-		for (i = 0; i < 4; i++) {
-			if (bufs[i].BufferType == SECBUFFER_DATA)
-				break;
-		}
-		if (i == 4) {
-			wpa_printf(MSG_DEBUG, "%s: No output data from "
-				   "DecryptMessage", __func__);
-			wpabuf_free(tmp);
-			return NULL;
-		}
-		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
-				"DecryptMessage",
-				bufs[i].pvBuffer, bufs[i].cbBuffer);
-		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
-		wpabuf_free(tmp);
-		return out;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
-		   __func__, (int) status);
-	wpabuf_free(tmp);
-	return NULL;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
-				     struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->write_alerts;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	struct tls_global *global = tls_ctx;
-	ALG_ID algs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-
-	if (conn == NULL)
-		return -1;
-
-	if (global->my_cert_store == NULL &&
-	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
-	    NULL) {
-		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		return -1;
-	}
-
-	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
-	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
-	algs[0] = CALG_RSA_KEYX;
-	conn->schannel_cred.cSupportedAlgs = 1;
-	conn->schannel_cred.palgSupportedAlgs = algs;
-	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-#ifdef UNICODE
-	status = global->sspi->AcquireCredentialsHandleW(
-		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
-		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->AcquireCredentialsHandleA(
-		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
-		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#endif /* UNICODE */
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
-			   "0x%x", __func__, (unsigned int) status);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8ee825..e4d0412 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
 /*
  * Driver interface definition
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -20,6 +20,7 @@
 #define WPA_SUPPLICANT_DRIVER_VERSION 4
 
 #include "common/defs.h"
+#include "common/ieee802_11_defs.h"
 #include "utils/list.h"
 
 #define HOSTAPD_CHAN_DISABLED 0x00000001
@@ -44,6 +45,9 @@
 #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
 
+/**
+ * enum reg_change_initiator - Regulatory change initiator
+ */
 enum reg_change_initiator {
 	REGDOM_SET_BY_CORE,
 	REGDOM_SET_BY_USER,
@@ -52,6 +56,9 @@
 	REGDOM_BEACON_HINT,
 };
 
+/**
+ * enum reg_type - Regulatory change types
+ */
 enum reg_type {
 	REGDOM_TYPE_UNKNOWN,
 	REGDOM_TYPE_COUNTRY,
@@ -84,8 +91,8 @@
 	 */
 	u8 max_tx_power;
 
-	/*
-	 * survey_list - Linked list of surveys
+	/**
+	 * survey_list - Linked list of surveys (struct freq_survey)
 	 */
 	struct dl_list survey_list;
 
@@ -104,7 +111,9 @@
 	long double interference_factor;
 #endif /* CONFIG_ACS */
 
-	/* DFS CAC time in milliseconds */
+	/**
+	 * dfs_cac_ms - DFS CAC time in milliseconds
+	 */
 	unsigned int dfs_cac_ms;
 };
 
@@ -190,7 +199,6 @@
 #define WPA_SCAN_NOISE_INVALID		BIT(1)
 #define WPA_SCAN_LEVEL_INVALID		BIT(2)
 #define WPA_SCAN_LEVEL_DBM		BIT(3)
-#define WPA_SCAN_AUTHENTICATED		BIT(4)
 #define WPA_SCAN_ASSOCIATED		BIT(5)
 
 /**
@@ -206,6 +214,9 @@
  * @tsf: Timestamp
  * @age: Age of the information in milliseconds (i.e., how many milliseconds
  * ago the last Beacon or Probe Response frame was received)
+ * @est_throughput: Estimated throughput in kbps (this is calculated during
+ * scan result processing if left zero by the driver wrapper)
+ * @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
  * @ie_len: length of the following IE field in octets
  * @beacon_ie_len: length of the following Beacon IE field in octets
  *
@@ -217,6 +228,11 @@
  * constructed of the IEs that are available. This field will also need to
  * include SSID in IE format. All drivers are encouraged to be extended to
  * report all IEs to make it easier to support future additions.
+ *
+ * This structure data is followed by ie_len octets of IEs from Probe Response
+ * frame (or if the driver does not indicate source of IEs, these may also be
+ * from Beacon frame). After the first set of IEs, another set of IEs may follow
+ * (with beacon_ie_len octets of data) if the driver provides both IE sets.
  */
 struct wpa_scan_res {
 	unsigned int flags;
@@ -229,15 +245,11 @@
 	int level;
 	u64 tsf;
 	unsigned int age;
+	unsigned int est_throughput;
+	int snr;
 	size_t ie_len;
 	size_t beacon_ie_len;
-	/*
-	 * Followed by ie_len octets of IEs from Probe Response frame (or if
-	 * the driver does not indicate source of IEs, these may also be from
-	 * Beacon frame). After the first set of IEs, another set of IEs may
-	 * follow (with beacon_ie_len octets of data) if the driver provides
-	 * both IE sets.
-	 */
+	/* Followed by ie_len + beacon_ie_len octets of IE data */
 };
 
 /**
@@ -330,7 +342,7 @@
 	 * is not needed anymore.
 	 */
 	struct wpa_driver_scan_filter {
-		u8 ssid[32];
+		u8 ssid[SSID_MAX_LEN];
 		size_t ssid_len;
 	} *filter_ssids;
 
@@ -374,6 +386,27 @@
 	 */
 	unsigned int low_priority:1;
 
+	/**
+	 * mac_addr_rand - Requests driver to randomize MAC address
+	 */
+	unsigned int mac_addr_rand:1;
+
+	/**
+	 * mac_addr - MAC address used with randomization. The address cannot be
+	 * a multicast one, i.e., bit 0 of byte 0 should not be set.
+	 */
+	const u8 *mac_addr;
+
+	/**
+	 * mac_addr_mask - MAC address mask used with randomization.
+	 *
+	 * Bits that are 0 in the mask should be randomized. Bits that are 1 in
+	 * the mask should be taken as is from mac_addr. The mask should not
+	 * allow the generation of a multicast address, i.e., bit 0 of byte 0
+	 * must be set.
+	 */
+	const u8 *mac_addr_mask;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -403,34 +436,95 @@
 	 */
 	int p2p;
 
+	/**
+	 * sae_data - SAE elements for Authentication frame
+	 *
+	 * This buffer starts with the Authentication transaction sequence
+	 * number field. If SAE is not used, this pointer is %NULL.
+	 */
 	const u8 *sae_data;
+
+	/**
+	 * sae_data_len - Length of sae_data buffer in octets
+	 */
 	size_t sae_data_len;
-
 };
 
+/**
+ * enum wps_mode - WPS mode
+ */
 enum wps_mode {
-	WPS_MODE_NONE /* no WPS provisioning being used */,
-	WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
-	WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
-			  */
+	/**
+	 * WPS_MODE_NONE - No WPS provisioning being used
+	 */
+	WPS_MODE_NONE,
+
+	/**
+	 * WPS_MODE_OPEN - WPS provisioning with AP that is in open mode
+	 */
+	WPS_MODE_OPEN,
+
+	/**
+	 * WPS_MODE_PRIVACY - WPS provisioning with AP that is using protection
+	 */
+	WPS_MODE_PRIVACY
 };
 
+/**
+ * struct hostapd_freq_params - Channel parameters
+ */
 struct hostapd_freq_params {
-	int mode;
-	int freq;
-	int channel;
-	/* for HT */
-	int ht_enabled;
-	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
-				 * secondary channel below primary, 1 = HT40
-				 * enabled, secondary channel above primary */
+	/**
+	 * mode - Mode/band (HOSTAPD_MODE_IEEE80211A, ..)
+	 */
+	enum hostapd_hw_mode mode;
 
-	/* for VHT */
+	/**
+	 * freq - Primary channel center frequency in MHz
+	 */
+	int freq;
+
+	/**
+	 * channel - Channel number
+	 */
+	int channel;
+
+	/**
+	 * ht_enabled - Whether HT is enabled
+	 */
+	int ht_enabled;
+
+	/**
+	 * sec_channel_offset - Secondary channel offset for HT40
+	 *
+	 * 0 = HT40 disabled,
+	 * -1 = HT40 enabled, secondary channel below primary,
+	 * 1 = HT40 enabled, secondary channel above primary
+	 */
+	int sec_channel_offset;
+
+	/**
+	 * vht_enabled - Whether VHT is enabled
+	 */
 	int vht_enabled;
 
-	/* valid for both HT and VHT, center_freq2 is non-zero
-	 * only for bandwidth 80 and an 80+80 channel */
-	int center_freq1, center_freq2;
+	/**
+	 * center_freq1 - Segment 0 center frequency in MHz
+	 *
+	 * Valid for both HT and VHT.
+	 */
+	int center_freq1;
+
+	/**
+	 * center_freq2 - Segment 1 center frequency in MHz
+	 *
+	 * Non-zero only for bandwidth 80 and an 80+80 channel
+	 */
+	int center_freq2;
+
+	/**
+	 * bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
+	 */
 	int bandwidth;
 };
 
@@ -679,17 +773,34 @@
 	int fixed_bssid;
 
 	/**
+	 * fixed_freq - Fix control channel in IBSS mode
+	 * 0 = don't fix control channel (default)
+	 * 1 = fix control channel; this prevents IBSS merging with another
+	 *	channel
+	 */
+	int fixed_freq;
+
+	/**
 	 * disable_ht - Disable HT (IEEE 802.11n) for this connection
 	 */
 	int disable_ht;
 
 	/**
-	 * HT Capabilities over-rides. Only bits set in the mask will be used,
-	 * and not all values are used by the kernel anyway. Currently, MCS,
-	 * MPDU and MSDU fields are used.
+	 * htcaps - HT Capabilities over-rides
+	 *
+	 * Only bits set in the mask will be used, and not all values are used
+	 * by the kernel anyway. Currently, MCS, MPDU and MSDU fields are used.
+	 *
+	 * Pointer to struct ieee80211_ht_capabilities.
 	 */
-	const u8 *htcaps;       /* struct ieee80211_ht_capabilities * */
-	const u8 *htcaps_mask;  /* struct ieee80211_ht_capabilities * */
+	const u8 *htcaps;
+
+	/**
+	 * htcaps_mask - HT Capabilities over-rides mask
+	 *
+	 * Pointer to struct ieee80211_ht_capabilities.
+	 */
+	const u8 *htcaps_mask;
 
 #ifdef CONFIG_VHT_OVERRIDES
 	/**
@@ -913,6 +1024,11 @@
 	int ap_max_inactivity;
 
 	/**
+	 * ctwindow - Client Traffic Window (in TUs)
+	 */
+	u8 p2p_go_ctwindow;
+
+	/**
 	 * smps_mode - SMPS mode
 	 *
 	 * SMPS mode to be used by the AP, specified as the relevant bits of
@@ -934,6 +1050,11 @@
 	 * freq - Channel parameters for dynamic bandwidth changes
 	 */
 	struct hostapd_freq_params *freq;
+
+	/**
+	 * reenable - Whether this is to re-enable beaconing
+	 */
+	int reenable;
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -943,6 +1064,7 @@
 	 * See NL80211_MESHCONF_* for all the mesh config parameters.
 	 */
 	unsigned int flags;
+	int peer_link_timeout;
 };
 
 struct wpa_driver_mesh_join_params {
@@ -951,10 +1073,9 @@
 	const int *basic_rates;
 	const u8 *ies;
 	int ie_len;
-	int freq;
+	struct hostapd_freq_params freq;
 	int beacon_int;
 	int max_peer_links;
-	enum ht_mode ht_mode;
 	struct wpa_driver_mesh_bss_params conf;
 #define WPA_DRIVER_MESH_FLAG_USER_MPM	0x00000001
 #define WPA_DRIVER_MESH_FLAG_DRIVER_MPM	0x00000002
@@ -975,6 +1096,9 @@
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
 #define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B	0x00000100
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192	0x00000200
+	/** Bitfield of supported key management suites */
 	unsigned int key_mgmt;
 
 #define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
@@ -990,95 +1114,104 @@
 #define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256	0x00000400
 #define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256	0x00000800
 #define WPA_DRIVER_CAPA_ENC_GTK_NOT_USED	0x00001000
+	/** Bitfield of supported cipher suites */
 	unsigned int enc;
 
 #define WPA_DRIVER_AUTH_OPEN		0x00000001
 #define WPA_DRIVER_AUTH_SHARED		0x00000002
 #define WPA_DRIVER_AUTH_LEAP		0x00000004
+	/** Bitfield of supported IEEE 802.11 authentication algorithms */
 	unsigned int auth;
 
-/* Driver generated WPA/RSN IE */
+/** Driver generated WPA/RSN IE */
 #define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
-/* Driver needs static WEP key setup after association command */
+/** Driver needs static WEP key setup after association command */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-/* Driver takes care of all DFS operations */
+/** Driver takes care of all DFS operations */
 #define WPA_DRIVER_FLAGS_DFS_OFFLOAD			0x00000004
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
  * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+/** Driver is for a wired Ethernet interface */
 #define WPA_DRIVER_FLAGS_WIRED		0x00000010
-/* Driver provides separate commands for authentication and association (SME in
+/** Driver provides separate commands for authentication and association (SME in
  * wpa_supplicant). */
 #define WPA_DRIVER_FLAGS_SME		0x00000020
-/* Driver supports AP mode */
+/** Driver supports AP mode */
 #define WPA_DRIVER_FLAGS_AP		0x00000040
-/* Driver needs static WEP key setup after association has been completed */
+/** Driver needs static WEP key setup after association has been completed */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
-/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+/** Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
 #define WPA_DRIVER_FLAGS_HT_2040_COEX			0x00000100
-/* Driver supports concurrent P2P operations */
+/** Driver supports concurrent P2P operations */
 #define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
-/*
+/**
  * Driver uses the initial interface as a dedicated management interface, i.e.,
  * it cannot be used for P2P group operations or non-P2P purposes.
  */
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
-/* This interface is P2P capable (P2P GO or P2P Client) */
+/** This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
-/* Driver supports station and key removal when stopping an AP */
+/** Driver supports station and key removal when stopping an AP */
 #define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT		0x00001000
-/*
+/**
  * Driver uses the initial interface for P2P management interface and non-P2P
  * purposes (e.g., connect to infra AP), but this interface cannot be used for
  * P2P group operations.
  */
 #define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
-/*
+/**
  * Driver is known to use sane error codes, i.e., when it indicates that
  * something (e.g., association) fails, there was indeed a failure and the
  * operation does not end up getting completed successfully later.
  */
 #define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
-/* Driver supports off-channel TX */
+/** Driver supports off-channel TX */
 #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
-/* Driver indicates TX status events for EAPOL Data frames */
+/** Driver indicates TX status events for EAPOL Data frames */
 #define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
-/* Driver indicates TX status events for Deauth/Disassoc frames */
+/** Driver indicates TX status events for Deauth/Disassoc frames */
 #define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
-/* Driver supports roaming (BSS selection) in firmware */
+/** Driver supports roaming (BSS selection) in firmware */
 #define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
-/* Driver supports operating as a TDLS peer */
+/** Driver supports operating as a TDLS peer */
 #define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
-/* Driver requires external TDLS setup/teardown/discovery */
+/** Driver requires external TDLS setup/teardown/discovery */
 #define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
-/* Driver indicates support for Probe Response offloading in AP mode */
+/** Driver indicates support for Probe Response offloading in AP mode */
 #define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
-/* Driver supports U-APSD in AP mode */
+/** Driver supports U-APSD in AP mode */
 #define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
-/* Driver supports inactivity timer in AP mode */
+/** Driver supports inactivity timer in AP mode */
 #define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
-/* Driver expects user space implementation of MLME in AP mode */
+/** Driver expects user space implementation of MLME in AP mode */
 #define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
-/* Driver supports SAE with user space SME */
+/** Driver supports SAE with user space SME */
 #define WPA_DRIVER_FLAGS_SAE				0x02000000
-/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+/** Driver makes use of OBSS scan mechanism in wpa_supplicant */
 #define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
-/* Driver supports IBSS (Ad-hoc) mode */
+/** Driver supports IBSS (Ad-hoc) mode */
 #define WPA_DRIVER_FLAGS_IBSS				0x08000000
-/* Driver supports radar detection */
+/** Driver supports radar detection */
 #define WPA_DRIVER_FLAGS_RADAR				0x10000000
-/* Driver supports a dedicated interface for P2P Device */
+/** Driver supports a dedicated interface for P2P Device */
 #define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
-/* Driver supports QoS Mapping */
+/** Driver supports QoS Mapping */
 #define WPA_DRIVER_FLAGS_QOS_MAPPING			0x40000000
-/* Driver supports CSA in AP mode */
+/** Driver supports CSA in AP mode */
 #define WPA_DRIVER_FLAGS_AP_CSA				0x80000000
-/* Driver supports mesh */
+/** Driver supports mesh */
 #define WPA_DRIVER_FLAGS_MESH			0x0000000100000000ULL
-/* Driver support ACS offload */
+/** Driver support ACS offload */
 #define WPA_DRIVER_FLAGS_ACS_OFFLOAD		0x0000000200000000ULL
-/* Driver supports key management offload */
+/** Driver supports key management offload */
 #define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD	0x0000000400000000ULL
+/** Driver supports TDLS channel switching */
+#define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH	0x0000000800000000ULL
+/** Driver supports IBSS with HT datarates */
+#define WPA_DRIVER_FLAGS_HT_IBSS		0x0000001000000000ULL
+/** Driver supports IBSS with VHT datarates */
+#define WPA_DRIVER_FLAGS_VHT_IBSS		0x0000002000000000ULL
 	u64 flags;
 
 #define WPA_DRIVER_SMPS_MODE_STATIC			0x00000001
@@ -1087,9 +1220,19 @@
 
 	unsigned int wmm_ac_supported:1;
 
+	unsigned int mac_addr_rand_scan_supported:1;
+	unsigned int mac_addr_rand_sched_scan_supported:1;
+
+	/** Maximum number of supported active probe SSIDs */
 	int max_scan_ssids;
+
+	/** Maximum number of supported active probe SSIDs for sched_scan */
 	int max_sched_scan_ssids;
+
+	/** Whether sched_scan (offloaded scanning) is supported */
 	int sched_scan_supported;
+
+	/** Maximum number of supported match sets for sched_scan */
 	int max_match_sets;
 
 	/**
@@ -1107,13 +1250,13 @@
 	 * probe_resp_offloads - Bitmap of supported protocols by the driver
 	 * for Probe Response offloading.
 	 */
-/* Driver Probe Response offloading support for WPS ver. 1 */
+/** Driver Probe Response offloading support for WPS ver. 1 */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
-/* Driver Probe Response offloading support for WPS ver. 2 */
+/** Driver Probe Response offloading support for WPS ver. 2 */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
-/* Driver Probe Response offloading support for P2P */
+/** Driver Probe Response offloading support for P2P */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
-/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
 	unsigned int probe_resp_offloads;
 
@@ -1135,11 +1278,11 @@
 
 	struct wowlan_triggers wowlan_triggers;
 
-/* Driver adds the DS Params Set IE in Probe Request frames */
+/** Driver adds the DS Params Set IE in Probe Request frames */
 #define WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES	0x00000001
-/* Driver adds the WFA TPC IE in Probe Request frames */
+/** Driver adds the WFA TPC IE in Probe Request frames */
 #define WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES		0x00000002
-/* Driver handles quiet period requests */
+/** Driver handles quiet period requests */
 #define WPA_DRIVER_FLAGS_QUIET				0x00000004
 /**
  * Driver is capable of inserting the current TX power value into the body of
@@ -1335,6 +1478,7 @@
 	int above_threshold;
 	int current_signal;
 	int avg_signal;
+	int avg_beacon_signal;
 	int current_noise;
 	int current_txrate;
 	enum chan_width chanwidth;
@@ -1434,6 +1578,7 @@
 
 enum drv_br_net_param {
 	DRV_BR_NET_PARAM_GARP_ACCEPT,
+	DRV_BR_MULTICAST_SNOOPING,
 };
 
 struct drv_acs_params {
@@ -1445,6 +1590,16 @@
 
 	/* Indicates whether HT40 is enabled */
 	int ht40_enabled;
+
+	/* Indicates whether VHT is enabled */
+	int vht_enabled;
+
+	/* Configured ACS channel width */
+	u16 ch_width;
+
+	/* ACS channel list info */
+	unsigned int ch_list_len;
+	const u8 *ch_list;
 };
 
 
@@ -2514,18 +2669,6 @@
 			  int encrypt);
 
 	/**
-	 * shared_freq - Get operating frequency of shared interface(s)
-	 * @priv: Private driver interface data
-	 * Returns: Operating frequency in MHz, 0 if no shared operation in
-	 * use, or -1 on failure
-	 *
-	 * This command can be used to request the current operating frequency
-	 * of any virtual interface that shares the same radio to provide
-	 * information for channel selection for other virtual interfaces.
-	 */
-	int (*shared_freq)(void *priv);
-
-	/**
 	 * get_noa - Get current Notice of Absence attribute payload
 	 * @priv: Private driver interface data
 	 * @buf: Buffer for returning NoA
@@ -2744,14 +2887,17 @@
 	 * set_rekey_info - Set rekey information
 	 * @priv: Private driver interface data
 	 * @kek: Current KEK
+	 * @kek_len: KEK length in octets
 	 * @kck: Current KCK
+	 * @kck_len: KCK length in octets
 	 * @replay_ctr: Current EAPOL-Key Replay Counter
 	 *
 	 * This optional function can be used to provide information for the
 	 * driver/firmware to process EAPOL-Key frames in Group Key Handshake
 	 * while the host (including wpa_supplicant) is sleeping.
 	 */
-	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+	void (*set_rekey_info)(void *priv, const u8 *kek, size_t kek_len,
+			       const u8 *kck, size_t kck_len,
 			       const u8 *replay_ctr);
 
 	/**
@@ -2903,6 +3049,33 @@
 	int (*del_tx_ts)(void *priv, u8 tsid, const u8 *addr);
 
 	/**
+	 * Enable channel-switching with TDLS peer
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the TDLS peer
+	 * @oper_class: Operating class of the switch channel
+	 * @params: Channel specification
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The function indicates to driver that it can start switching to a
+	 * different channel with a specified TDLS peer. The switching is
+	 * assumed on until canceled with tdls_disable_channel_switch().
+	 */
+	int (*tdls_enable_channel_switch)(
+		void *priv, const u8 *addr, u8 oper_class,
+		const struct hostapd_freq_params *params);
+
+	/**
+	 * Disable channel switching with TDLS peer
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the TDLS peer
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates to the driver that it should stop switching
+	 * with a given TDLS peer.
+	 */
+	int (*tdls_disable_channel_switch)(void *priv, const u8 *addr);
+
+	/**
 	 * start_dfs_cac - Listen for radar interference on the channel
 	 * @priv: Private driver interface data
 	 * @freq: Channel parameters
@@ -3611,7 +3784,7 @@
 	EVENT_CONNECT_FAILED_REASON,
 
 	/**
-	 * EVENT_RADAR_DETECTED - Notify of radar detection
+	 * EVENT_DFS_RADAR_DETECTED - Notify of radar detection
 	 *
 	 * A radar has been detected on the supplied frequency, hostapd should
 	 * react accordingly (e.g., change channel).
@@ -3619,14 +3792,14 @@
 	EVENT_DFS_RADAR_DETECTED,
 
 	/**
-	 * EVENT_CAC_FINISHED - Notify that channel availability check has been completed
+	 * EVENT_DFS_CAC_FINISHED - Notify that channel availability check has been completed
 	 *
 	 * After a successful CAC, the channel can be marked clear and used.
 	 */
 	EVENT_DFS_CAC_FINISHED,
 
 	/**
-	 * EVENT_CAC_ABORTED - Notify that channel availability check has been aborted
+	 * EVENT_DFS_CAC_ABORTED - Notify that channel availability check has been aborted
 	 *
 	 * The CAC was not successful, and the channel remains in the previous
 	 * state. This may happen due to a radar beeing detected or other
@@ -3635,7 +3808,7 @@
 	EVENT_DFS_CAC_ABORTED,
 
 	/**
-	 * EVENT_DFS_CAC_NOP_FINISHED - Notify that non-occupancy period is over
+	 * EVENT_DFS_NOP_FINISHED - Notify that non-occupancy period is over
 	 *
 	 * The channel which was previously unavailable is now available again.
 	 */
@@ -3684,6 +3857,15 @@
 	 * in device.
 	 */
 	EVENT_ACS_CHANNEL_SELECTED,
+
+	/**
+	 * EVENT_DFS_CAC_STARTED - Notify that channel availability check has
+	 * been started.
+	 *
+	 * This event indicates that channel availability check has been started
+	 * on a DFS frequency by a driver that supports DFS Offload.
+	 */
+	EVENT_DFS_CAC_STARTED,
 };
 
 
@@ -3967,7 +4149,8 @@
 		u8 peer[ETH_ALEN];
 		enum {
 			TDLS_REQUEST_SETUP,
-			TDLS_REQUEST_TEARDOWN
+			TDLS_REQUEST_TEARDOWN,
+			TDLS_REQUEST_DISCOVER,
 		} oper;
 		u16 reason_code; /* for teardown */
 	} tdls;
@@ -4330,7 +4513,7 @@
 	 * survey_results - Survey result data for EVENT_SURVEY
 	 * @freq_filter: Requested frequency survey filter, 0 if request
 	 *	was for all survey data
-	 * @survey_list: Linked list of survey data
+	 * @survey_list: Linked list of survey data (struct freq_survey)
 	 */
 	struct survey_results {
 		unsigned int freq_filter;
@@ -4375,10 +4558,18 @@
 	 * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
 	 * @pri_channel: Selected primary channel
 	 * @sec_channel: Selected secondary channel
+	 * @vht_seg0_center_ch: VHT mode Segment0 center channel
+	 * @vht_seg1_center_ch: VHT mode Segment1 center channel
+	 * @ch_width: Selected Channel width by driver. Driver may choose to
+	 *	change hostapd configured ACS channel width due driver internal
+	 *	channel restrictions.
 	 */
 	struct acs_selected_channels {
 		u8 pri_channel;
 		u8 sec_channel;
+		u8 vht_seg0_center_ch;
+		u8 vht_seg1_center_ch;
+		u16 ch_width;
 	} acs_selected_channels;
 };
 
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 350d505..b8e7864 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1694,6 +1694,13 @@
 	struct atheros_driver_data *drv = priv;
 
 	atheros_reset_appfilter(drv);
+
+	if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
+		wpabuf_free(drv->wpa_ie);
+		wpabuf_free(drv->wps_beacon_ie);
+		wpabuf_free(drv->wps_probe_resp_ie);
+		atheros_set_opt_ie(priv, NULL, 0);
+	}
 	netlink_deinit(drv->netlink);
 	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
 	if (drv->ioctl_sock >= 0)
@@ -1704,9 +1711,6 @@
 		l2_packet_deinit(drv->sock_xmit);
 	if (drv->sock_raw)
 		l2_packet_deinit(drv->sock_raw);
-	wpabuf_free(drv->wpa_ie);
-	wpabuf_free(drv->wps_beacon_ie);
-	wpabuf_free(drv->wps_probe_resp_ie);
 	free(drv);
 }
 
@@ -1810,7 +1814,7 @@
 	wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
 			params->assocresp_ies);
 
-#if defined(CONFIG_HS20) && defined(IEEE80211_PARAM_OSEN)
+#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN))
 	if (params->osen) {
 		struct wpa_bss_params bss_params;
 
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index c377970..0f1a0f6 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1344,7 +1344,12 @@
 	*pos++ = 1;
 	*pos++ = sr->isr_erp;
 
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len,
+		  sr->isr_ie_len);
+#else
 	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+#endif
 	pos += sr->isr_ie_len;
 
 	result->ie_len = pos - (u8 *)(result + 1);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index f897c11..aebea8c 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -79,6 +79,7 @@
 	E2S(AVOID_FREQUENCIES);
 	E2S(NEW_PEER_CANDIDATE);
 	E2S(ACS_CHANNEL_SELECTED);
+	E2S(DFS_CAC_STARTED);
 	}
 
 	return "UNKNOWN";
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
index a9d3e76..4c1e6d6 100644
--- a/src/drivers/driver_hostap.h
+++ b/src/drivers/driver_hostap.h
@@ -192,7 +192,7 @@
 		} mlme;
 		struct {
 			u8 ssid_len;
-			u8 ssid[32];
+			u8 ssid[SSID_MAX_LEN];
 		} scan_req;
 	} u;
 };
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 4953af6..669f1b8 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -709,11 +709,11 @@
 /* Disconnect by setting SSID to random (i.e., likely not used). */
 static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
 {
-	char ssid[32];
+	char ssid[SSID_MAX_LEN];
 	int i;
-	for (i = 0; i < 32; i++)
+	for (i = 0; i < SSID_MAX_LEN; i++)
 		ssid[i] = rand() & 0xff;
-	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
+	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, SSID_MAX_LEN);
 }
 
 
@@ -806,7 +806,7 @@
 	if (wpa_scan_get_ie(r, WLAN_EID_SSID))
 		return r; /* SSID IE already present */
 
-	if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
+	if (ssid->SsidLength == 0 || ssid->SsidLength > SSID_MAX_LEN)
 		return r; /* No valid SSID inside scan data */
 
 	nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 592ff71..640e099 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@@ -132,6 +132,22 @@
 					eloop_sock_handler handler,
 					void *eloop_data)
 {
+#ifdef CONFIG_LIBNL20
+	/*
+	 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
+	 * by default. It is possible to hit that limit in some cases where
+	 * operations are blocked, e.g., with a burst of Deauthentication frames
+	 * to hostapd and STA entry deletion. Try to increase the buffer to make
+	 * this less likely to occur.
+	 */
+	if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Could not set nl_socket RX buffer size: %s",
+			   strerror(errno));
+		/* continue anyway with the default (smaller) buffer */
+	}
+#endif /* CONFIG_LIBNL20 */
+
 	nl_socket_set_nonblocking(*handle);
 	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
 				 eloop_data, *handle);
@@ -148,6 +164,7 @@
 
 
 static void nl80211_global_deinit(void *priv);
+static void nl80211_check_global(struct nl80211_global *global);
 
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
@@ -281,6 +298,28 @@
 }
 
 
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+	/*
+	 * Clear nlmsg data, e.g., to make sure key material is not left in
+	 * heap memory for unnecessarily long time.
+	 */
+	if (msg) {
+		struct nlmsghdr *hdr = nlmsg_hdr(msg);
+		void *data = nlmsg_data(hdr);
+		/*
+		 * This would use nlmsg_datalen() or the older nlmsg_len() if
+		 * only libnl were to maintain a stable API.. Neither will work
+		 * with all released versions, so just calculate the length
+		 * here.
+		 */
+		int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+		os_memset(data, 0, len);
+	}
+}
+
+
 static int send_and_recv(struct nl80211_global *global,
 			 struct nl_handle *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
@@ -320,6 +359,8 @@
 	}
  out:
 	nl_cb_put(cb);
+	if (!valid_handler && valid_data == (void *) -1)
+		nl80211_nlmsg_clear(msg);
 	nlmsg_free(msg);
 	return err;
 }
@@ -824,6 +865,7 @@
 		return 1;
 
 	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+		nl80211_check_global(drv->global);
 		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
 			   "interface");
 		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
@@ -912,16 +954,21 @@
 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
 	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+		namebuf[0] = '\0';
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
-		    linux_iface_up(drv->global->ioctl_sock,
-				   drv->first_bss->ifname) > 0) {
+		    linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
 			drv->ignore_if_down_event = 0;
 			return;
 		}
-		wpa_printf(MSG_WARNING, "nl80211: Interface down");
-		if (drv->ignore_if_down_event) {
+		wpa_printf(MSG_WARNING, "nl80211: Interface down (%s/%s)",
+			   namebuf, ifname);
+		if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Not the main interface (%s) - do not indicate interface down",
+				   drv->first_bss->ifname);
+		} else if (drv->ignore_if_down_event) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event generated by mode change");
 			drv->ignore_if_down_event = 0;
@@ -944,8 +991,7 @@
 
 	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
-		    linux_iface_up(drv->global->ioctl_sock,
-				   drv->first_bss->ifname) == 0) {
+		    linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is down",
 				   namebuf);
@@ -1141,6 +1187,7 @@
 	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
 		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
 		[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
+		[NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
 	};
 	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
 	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1169,6 +1216,13 @@
 	else
 		sig_change->avg_signal = 0;
 
+	if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
+		sig_change->avg_beacon_signal =
+			(s8)
+			nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
+	else
+		sig_change->avg_beacon_signal = 0;
+
 	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
 		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
 				     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1437,6 +1491,33 @@
 }
 
 
+static void nl80211_check_global(struct nl80211_global *global)
+{
+	struct nl_handle *handle;
+	const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
+	int ret;
+	unsigned int i;
+
+	/*
+	 * Try to re-add memberships to handle case of cfg80211 getting reloaded
+	 * and all registration having been cleared.
+	 */
+	handle = (void *) (((intptr_t) global->nl_event) ^
+			   ELOOP_SOCKET_INVALID);
+
+	for (i = 0; groups[i]; i++) {
+		ret = nl_get_multicast_id(global, "nl80211", groups[i]);
+		if (ret >= 0)
+			ret = nl_socket_add_membership(handle, ret);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
+				   groups[i], ret, strerror(-ret));
+		}
+	}
+}
+
+
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -1559,6 +1640,14 @@
 	drv->ctx = ctx;
 	drv->hostapd = !!hostapd;
 	drv->eapol_sock = -1;
+
+	/*
+	 * There is no driver capability flag for this, so assume it is
+	 * supported and disable this on first attempt to use if the driver
+	 * rejects the command due to missing support.
+	 */
+	drv->set_rekey_offload = 1;
+
 	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
 	drv->if_indices = drv->default_if_indices;
 
@@ -1622,6 +1711,7 @@
 	}
 
 	if (drv->global) {
+		nl80211_check_global(drv->global);
 		dl_list_add(&drv->global->interfaces, &drv->list);
 		drv->in_interface_list = 1;
 	}
@@ -1812,11 +1902,11 @@
 
 	/* WMM-AC ADDTS Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
-		return -1;
+		ret = -1;
 
 	/* WMM-AC DELTS */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
-		return -1;
+		ret = -1;
 
 	/* Radio Measurement - Neighbor Report Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
@@ -2017,6 +2107,60 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
+{
+	/* struct wpa_driver_nl80211_data *drv = arg; */
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: QCA vendor test command response received");
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+		wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
+		return NL_SKIP;
+	}
+
+	wpa_hexdump(MSG_DEBUG,
+		    "nl80211: Received QCA vendor test command response",
+		    nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+		    nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
+
+	return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	struct nl_msg *msg;
+	struct nlattr *params;
+	int ret;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_TEST) ||
+	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
+		nlmsg_free(msg);
+		return;
+	}
+	nla_nest_end(msg, params);
+
+	ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: QCA vendor test command returned %d (%s)",
+		   ret, strerror(-ret));
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
 				   const u8 *set_addr, int first,
@@ -2103,6 +2247,9 @@
 				       drv, drv->ctx);
 	}
 
+	if (drv->vendor_cmd_test_avail)
+		qca_vendor_test(drv);
+
 	return 0;
 }
 
@@ -2150,7 +2297,11 @@
 			nl80211_handle_destroy(drv->rtnl_sk);
 	}
 	if (bss->added_bridge) {
-		linux_set_iface_flags(drv->global->ioctl_sock, bss->brname, 0);
+		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+					  0) < 0)
+			wpa_printf(MSG_INFO,
+				   "nl80211: Could not set bridge %s down",
+				   bss->brname);
 		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
@@ -2327,10 +2478,11 @@
 	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
 			QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
 	    nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+		nl80211_nlmsg_clear(msg);
 		nlmsg_free(msg);
 		return -1;
 	}
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Key management set key failed: ret=%d (%s)",
@@ -2422,7 +2574,7 @@
 	if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
 	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
 		ret = 0;
 	if (ret)
@@ -2442,7 +2594,10 @@
 	msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
 	if (!msg ||
 	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
-	    nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+	    nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
+			       alg == WPA_ALG_BIP_GMAC_128 ||
+			       alg == WPA_ALG_BIP_GMAC_256 ||
+			       alg == WPA_ALG_BIP_CMAC_256) ?
 			 NL80211_ATTR_KEY_DEFAULT_MGMT :
 			 NL80211_ATTR_KEY_DEFAULT))
 		goto fail;
@@ -2473,6 +2628,7 @@
 	return ret;
 
 fail:
+	nl80211_nlmsg_clear(msg);
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -3040,9 +3196,25 @@
 }
 
 
+static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
+{
+	u8 rates[NL80211_MAX_SUPP_RATES];
+	u8 rates_len = 0;
+	int i;
+
+	if (!basic_rates)
+		return 0;
+
+	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+		rates[rates_len++] = basic_rates[i] / 5;
+
+	return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+}
+
+
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 			   int slot, int ht_opmode, int ap_isolate,
-			   int *basic_rates)
+			   const int *basic_rates)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
@@ -3057,27 +3229,13 @@
 	    (ht_opmode >= 0 &&
 	     nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
 	    (ap_isolate >= 0 &&
-	     nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)))
-		goto fail;
-
-	if (basic_rates) {
-		u8 rates[NL80211_MAX_SUPP_RATES];
-		u8 rates_len = 0;
-		int i;
-
-		for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
-		     i++)
-			rates[rates_len++] = basic_rates[i] / 5;
-
-		if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-			    rates))
-			goto fail;
+	     nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
+	    nl80211_put_basic_rates(msg, basic_rates)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
 	}
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
-fail:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -3128,6 +3286,18 @@
 }
 
 
+static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
+{
+	if (beacon_int > 0) {
+		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", beacon_int);
+		return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+				   beacon_int);
+	}
+
+	return 0;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
 				     struct wpa_driver_ap_params *params)
 {
@@ -3142,7 +3312,7 @@
 	u32 suites[10], suite;
 	u32 ver;
 
-	beacon_set = bss->beacon_set;
+	beacon_set = params->reenable ? 0 : bss->beacon_set;
 
 	wpa_printf(MSG_INFO, "nl80211: Set beacon (beacon_set=%d)",
 		   beacon_set);
@@ -3163,8 +3333,7 @@
 		    params->head) ||
 	    nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
 		    params->tail) ||
-	    nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-			params->beacon_int) ||
+	    nl80211_put_beacon_int(msg, params->beacon_int) ||
 	    nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
 	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
 		goto fail;
@@ -3308,6 +3477,21 @@
 			goto fail;
 	}
 
+#ifdef CONFIG_P2P
+	if (params->p2p_go_ctwindow > 0) {
+		if (drv->p2p_go_ctwindow_supported) {
+			wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
+				   params->p2p_go_ctwindow);
+			if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
+				       params->p2p_go_ctwindow))
+				goto fail;
+		} else {
+			wpa_printf(MSG_INFO,
+				   "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -3350,14 +3534,19 @@
 
 
 static int nl80211_put_freq_params(struct nl_msg *msg,
-				   struct hostapd_freq_params *freq)
+				   const struct hostapd_freq_params *freq)
 {
+	wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
 	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
 		return -ENOBUFS;
 
+	wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
+	wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
+
 	if (freq->vht_enabled) {
 		enum nl80211_chan_width cw;
 
+		wpa_printf(MSG_DEBUG, "  * bandwidth=%d", freq->bandwidth);
 		switch (freq->bandwidth) {
 		case 20:
 			cw = NL80211_CHAN_WIDTH_20;
@@ -3378,6 +3567,11 @@
 			return -EINVAL;
 		}
 
+		wpa_printf(MSG_DEBUG, "  * channel_width=%d", cw);
+		wpa_printf(MSG_DEBUG, "  * center_freq1=%d",
+			   freq->center_freq1);
+		wpa_printf(MSG_DEBUG, "  * center_freq2=%d",
+			   freq->center_freq2);
 		if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
 		    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
 				freq->center_freq1) ||
@@ -3388,6 +3582,8 @@
 	} else if (freq->ht_enabled) {
 		enum nl80211_channel_type ct;
 
+		wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
+			   freq->sec_channel_offset);
 		switch (freq->sec_channel_offset) {
 		case -1:
 			ct = NL80211_CHAN_HT40MINUS;
@@ -3400,6 +3596,7 @@
 			break;
 		}
 
+		wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
 		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
 			return -ENOBUFS;
 	}
@@ -4112,7 +4309,8 @@
 		return -1;
 	}
 
-	if (nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
+	if (params->freq.freq &&
+	    nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
 		if (old_mode != nlmode)
 			wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
 		nl80211_remove_monitor_interface(drv);
@@ -4150,6 +4348,48 @@
 }
 
 
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+				    struct wpa_driver_associate_params *params)
+{
+	if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+		return -1;
+
+	if (params->htcaps && params->htcaps_mask) {
+		int sz = sizeof(struct ieee80211_ht_capabilities);
+		wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
+		wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
+			    params->htcaps_mask, sz);
+		if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+			    params->htcaps) ||
+		    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+			    params->htcaps_mask))
+			return -1;
+	}
+
+#ifdef CONFIG_VHT_OVERRIDES
+	if (params->disable_vht) {
+		wpa_printf(MSG_DEBUG, "  * VHT disabled");
+		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+			return -1;
+	}
+
+	if (params->vhtcaps && params->vhtcaps_mask) {
+		int sz = sizeof(struct ieee80211_vht_capabilities);
+		wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
+		wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
+			    params->vhtcaps_mask, sz);
+		if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+			    params->vhtcaps) ||
+		    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+			    params->vhtcaps_mask))
+			return -1;
+	}
+#endif /* CONFIG_VHT_OVERRIDES */
+
+	return 0;
+}
+
+
 static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
 				   struct wpa_driver_associate_params *params)
 {
@@ -4177,24 +4417,10 @@
 	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
 	drv->ssid_len = params->ssid_len;
 
-	wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq.freq);
-	wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", params->freq.ht_enabled);
-	wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
-		   params->freq.sec_channel_offset);
-	wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", params->freq.vht_enabled);
-	wpa_printf(MSG_DEBUG, "  * center_freq1=%d", params->freq.center_freq1);
-	wpa_printf(MSG_DEBUG, "  * center_freq2=%d", params->freq.center_freq2);
-	wpa_printf(MSG_DEBUG, "  * bandwidth=%d", params->freq.bandwidth);
-	if (nl80211_put_freq_params(msg, &params->freq) < 0)
+	if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
+	    nl80211_put_beacon_int(msg, params->beacon_int))
 		goto fail;
 
-	if (params->beacon_int > 0) {
-		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-		if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-				params->beacon_int))
-			goto fail;
-	}
-
 	ret = nl80211_set_conn_keys(params, msg);
 	if (ret)
 		goto fail;
@@ -4206,6 +4432,12 @@
 			goto fail;
 	}
 
+	if (params->fixed_freq) {
+		wpa_printf(MSG_DEBUG, "  * fixed_freq");
+		if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
+			goto fail;
+	}
+
 	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -4224,6 +4456,9 @@
 			goto fail;
 	}
 
+	if (nl80211_ht_vht_overrides(msg, params) < 0)
+		return -1;
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
@@ -4351,7 +4586,8 @@
 	    params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
-	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
 		int mgmt = WLAN_AKM_SUITE_PSK;
 
 		switch (params->key_mgmt_suite) {
@@ -4379,6 +4615,9 @@
 		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
 			mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
 			break;
+		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+			mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+			break;
 		case WPA_KEY_MGMT_PSK:
 		default:
 			mgmt = WLAN_AKM_SUITE_PSK;
@@ -4405,41 +4644,9 @@
 			return -1;
 	}
 
-	if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+	if (nl80211_ht_vht_overrides(msg, params) < 0)
 		return -1;
 
-	if (params->htcaps && params->htcaps_mask) {
-		int sz = sizeof(struct ieee80211_ht_capabilities);
-		wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
-		wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
-			    params->htcaps_mask, sz);
-		if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
-			    params->htcaps) ||
-		    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-			    params->htcaps_mask))
-			return -1;
-	}
-
-#ifdef CONFIG_VHT_OVERRIDES
-	if (params->disable_vht) {
-		wpa_printf(MSG_DEBUG, "  * VHT disabled");
-		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
-			return -1;
-	}
-
-	if (params->vhtcaps && params->vhtcaps_mask) {
-		int sz = sizeof(struct ieee80211_vht_capabilities);
-		wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
-		wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
-			    params->vhtcaps_mask, sz);
-		if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
-			    params->vhtcaps) ||
-		    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-			    params->vhtcaps_mask))
-			return -1;
-	}
-#endif /* CONFIG_VHT_OVERRIDES */
-
 	if (params->p2p)
 		wpa_printf(MSG_DEBUG, "  * P2P group");
 
@@ -5169,6 +5376,8 @@
 
 	data.inactive_msec = (unsigned long) -1;
 	ret = i802_read_sta_data(priv, &data, addr);
+	if (ret == -ENOENT)
+		return -ENOENT;
 	if (ret || data.inactive_msec == (unsigned long) -1)
 		return -1;
 	return data.inactive_msec / 1000;
@@ -6313,47 +6522,6 @@
 }
 
 
-static int wpa_driver_nl80211_shared_freq(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct wpa_driver_nl80211_data *driver;
-	int freq = 0;
-
-	/*
-	 * If the same PHY is in connected state with some other interface,
-	 * then retrieve the assoc freq.
-	 */
-	wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
-		   drv->phyname);
-
-	dl_list_for_each(driver, &drv->global->interfaces,
-			 struct wpa_driver_nl80211_data, list) {
-		if (drv == driver ||
-		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
-		    !driver->associated)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
-			   MACSTR,
-			   driver->phyname, driver->first_bss->ifname,
-			   MAC2STR(driver->first_bss->addr));
-		if (is_ap_interface(driver->nlmode))
-			freq = driver->first_bss->freq;
-		else
-			freq = nl80211_get_assoc_freq(driver);
-		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
-			   drv->phyname, freq);
-	}
-
-	if (!freq)
-		wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
-			   "PHY (%s) in associated state", drv->phyname);
-
-	return freq;
-}
-
-
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
 			      int encrypt)
 {
@@ -6699,27 +6867,39 @@
 }
 
 
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+				   const u8 *kck, size_t kck_len,
 				   const u8 *replay_ctr)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nlattr *replay_nested;
 	struct nl_msg *msg;
+	int ret;
 
+	if (!drv->set_rekey_offload)
+		return;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
 	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
 	    !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
-	    nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
-	    nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+	    nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+	    nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
 	    nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
 		    replay_ctr)) {
+		nl80211_nlmsg_clear(msg);
 		nlmsg_free(msg);
 		return;
 	}
 
 	nla_nest_end(msg, replay_nested);
 
-	send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+	if (ret == -EOPNOTSUPP) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Driver does not support rekey offload");
+		drv->set_rekey_offload = 0;
+	}
 }
 
 
@@ -6767,6 +6947,7 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
+	int ret;
 
 	if (!drv->poll_command_supported) {
 		nl80211_send_null_frame(bss, own_addr, addr, qos);
@@ -6779,7 +6960,12 @@
 		return;
 	}
 
-	send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
+			   MACSTR " failed: ret=%d (%s)",
+			   MAC2STR(addr), ret, strerror(-ret));
+	}
 }
 
 
@@ -6945,6 +7131,62 @@
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
 
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+				   const struct hostapd_freq_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+		return -EOPNOTSUPP;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+		   " oper_class=%u freq=%u",
+		   MAC2STR(addr), oper_class, params->freq);
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+	if (!msg ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+	    (ret = nl80211_put_freq_params(msg, params))) {
+		nlmsg_free(msg);
+		wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+		return ret;
+	}
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+		return -EOPNOTSUPP;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+		   MAC2STR(addr));
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+	if (!msg ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+		nlmsg_free(msg);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Could not build TDLS cancel chan switch");
+		return -ENOBUFS;
+	}
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
 #endif /* CONFIG TDLS */
 
 
@@ -7229,7 +7471,9 @@
 				  "capa.max_stations=%u\n"
 				  "capa.probe_resp_offloads=0x%x\n"
 				  "capa.max_acl_mac_addrs=%u\n"
-				  "capa.num_multichan_concurrent=%u\n",
+				  "capa.num_multichan_concurrent=%u\n"
+				  "capa.mac_addr_rand_sched_scan_supported=%d\n"
+				  "capa.mac_addr_rand_scan_supported=%d\n",
 				  drv->capa.key_mgmt,
 				  drv->capa.enc,
 				  drv->capa.auth,
@@ -7243,7 +7487,9 @@
 				  drv->capa.max_stations,
 				  drv->capa.probe_resp_offloads,
 				  drv->capa.max_acl_mac_addrs,
-				  drv->capa.num_multichan_concurrent);
+				  drv->capa.num_multichan_concurrent,
+				  drv->capa.mac_addr_rand_sched_scan_supported,
+				  drv->capa.mac_addr_rand_scan_supported);
 		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
@@ -7676,84 +7922,35 @@
 }
 
 
-static int
-wpa_driver_nl80211_join_mesh(void *priv,
+static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
+			       size_t mesh_id_len)
+{
+	if (mesh_id) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * Mesh ID (SSID)",
+				  mesh_id, mesh_id_len);
+		return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
+	}
+
+	return 0;
+}
+
+
+static int nl80211_join_mesh(struct i802_bss *bss,
 			     struct wpa_driver_mesh_join_params *params)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nlattr *container;
-	int ret = 0;
+	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
-	if (!msg)
+	if (!msg ||
+	    nl80211_put_freq_params(msg, &params->freq) ||
+	    nl80211_put_basic_rates(msg, params->basic_rates) ||
+	    nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
+	    nl80211_put_beacon_int(msg, params->beacon_int))
 		goto fail;
-	if (params->freq) {
-		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
-			goto fail;
-	}
-
-	if (params->ht_mode) {
-		unsigned int ht_value;
-		char *ht_mode = "";
-
-		switch (params->ht_mode) {
-		default:
-		case CHAN_NO_HT:
-			ht_value = NL80211_CHAN_NO_HT;
-			ht_mode = "NOHT";
-			break;
-		case CHAN_HT20:
-			ht_value = NL80211_CHAN_HT20;
-			ht_mode = "HT20";
-			break;
-		case CHAN_HT40PLUS:
-			ht_value = NL80211_CHAN_HT40PLUS;
-			ht_mode = "HT40+";
-			break;
-		case CHAN_HT40MINUS:
-			ht_value = NL80211_CHAN_HT40MINUS;
-			ht_mode = "HT40-";
-			break;
-		}
-		wpa_printf(MSG_DEBUG, "  * ht_mode=%s", ht_mode);
-		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
-			goto fail;
-	}
-
-	if (params->basic_rates) {
-		u8 rates[NL80211_MAX_SUPP_RATES];
-		u8 rates_len = 0;
-		int i;
-
-		for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
-			if (params->basic_rates[i] < 0)
-				break;
-			rates[rates_len++] = params->basic_rates[i] / 5;
-		}
-
-		if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-			    rates))
-			goto fail;
-	}
-
-	if (params->meshid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-				  params->meshid, params->meshid_len);
-		if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
-			    params->meshid))
-			goto fail;
-	}
-
-	if (params->beacon_int > 0) {
-		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-		if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-				params->beacon_int))
-			goto fail;
-	}
 
 	wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
 
@@ -7792,6 +7989,17 @@
 	    nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
 			params->max_peer_links))
 		goto fail;
+
+	/*
+	 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+	 * the timer could disconnect stations even in that case.
+	 */
+	if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+			params->conf.peer_link_timeout)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+		goto fail;
+	}
+
 	nla_nest_end(msg, container);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7802,7 +8010,7 @@
 		goto fail;
 	}
 	ret = 0;
-	bss->freq = params->freq;
+	bss->freq = params->freq.freq;
 	wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -7811,6 +8019,37 @@
 }
 
 
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+			     struct wpa_driver_mesh_join_params *params)
+{
+	struct i802_bss *bss = priv;
+	int ret, timeout;
+
+	timeout = params->conf.peer_link_timeout;
+
+	/* Disable kernel inactivity timer */
+	if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+		params->conf.peer_link_timeout = 0;
+
+	ret = nl80211_join_mesh(bss, params);
+	if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Mesh join retry for peer_link_timeout");
+		/*
+		 * Old kernel does not support setting
+		 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
+		 * into future from peer_link_timeout.
+		 */
+		params->conf.peer_link_timeout = timeout + 60;
+		ret = nl80211_join_mesh(priv, params);
+	}
+
+	params->conf.peer_link_timeout = timeout;
+	return ret;
+}
+
+
 static int wpa_driver_nl80211_leave_mesh(void *priv)
 {
 	struct i802_bss *bss = priv;
@@ -8033,7 +8272,7 @@
 {
 	switch (attr) {
 	case DRV_BR_PORT_ATTR_PROXYARP:
-		return "proxyarp";
+		return "proxyarp_wifi";
 	case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
 		return "hairpin_mode";
 	}
@@ -8068,9 +8307,9 @@
 	switch (param) {
 	case DRV_BR_NET_PARAM_GARP_ACCEPT:
 		return "arp_accept";
+	default:
+		return NULL;
 	}
-
-	return NULL;
 }
 
 
@@ -8082,6 +8321,13 @@
 	const char *param_txt;
 	int ip_version = 4;
 
+	if (param == DRV_BR_MULTICAST_SNOOPING) {
+		os_snprintf(path, sizeof(path),
+			    "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+			    bss->brname);
+		goto set_val;
+	}
+
 	param_txt = drv_br_net_param_str(param);
 	if (param_txt == NULL)
 		return -EINVAL;
@@ -8097,6 +8343,7 @@
 	os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
 		    ip_version, bss->brname, param_txt);
 
+set_val:
 	if (linux_write_system_file(path, val))
 		return -1;
 
@@ -8143,12 +8390,24 @@
 	    (params->ht_enabled &&
 	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
 	    (params->ht40_enabled &&
-	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
+	    (params->vht_enabled &&
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+	    nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+			params->ch_width) ||
+	    (params->ch_list_len &&
+	     nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
+		     params->ch_list))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
 	nla_nest_end(msg, data);
 
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
+		   params->vht_enabled, params->ch_width, params->ch_list_len);
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
@@ -8218,7 +8477,6 @@
 	.signal_monitor = nl80211_signal_monitor,
 	.signal_poll = nl80211_signal_poll,
 	.send_frame = nl80211_send_frame,
-	.shared_freq = wpa_driver_nl80211_shared_freq,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
 	.add_pmkid = nl80211_add_pmkid,
@@ -8232,6 +8490,8 @@
 #ifdef CONFIG_TDLS
 	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
 	.tdls_oper = nl80211_tdls_oper,
+	.tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+	.tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
 #endif /* CONFIG_TDLS */
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
 	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 6892b31..b5071b4 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -110,7 +110,7 @@
 	u8 bssid[ETH_ALEN];
 	u8 prev_bssid[ETH_ALEN];
 	int associated;
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	enum nl80211_iftype nlmode;
 	enum nl80211_iftype ap_scan_as_station;
@@ -136,12 +136,15 @@
 	unsigned int start_iface_up:1;
 	unsigned int test_use_roc_tx:1;
 	unsigned int ignore_deauth_event:1;
+	unsigned int vendor_cmd_test_avail:1;
 	unsigned int roaming_vendor_cmd_avail:1;
 	unsigned int dfs_vendor_cmd_avail:1;
 	unsigned int have_low_prio_scan:1;
 	unsigned int force_connect_cmd:1;
 	unsigned int addr_changed:1;
 	unsigned int get_features_vendor_cmd_avail:1;
+	unsigned int set_rekey_offload:1;
+	unsigned int p2p_go_ctwindow_supported:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
@@ -166,7 +169,7 @@
 	/* From failed authentication command */
 	int auth_freq;
 	u8 auth_bssid_[ETH_ALEN];
-	u8 auth_ssid[32];
+	u8 auth_ssid[SSID_MAX_LEN];
 	size_t auth_ssid_len;
 	int auth_alg;
 	u8 *auth_ie;
@@ -267,5 +270,6 @@
 int wpa_driver_nl80211_stop_sched_scan(void *priv);
 struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
 void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
 
 #endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 330ebdf..ba1e240 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211 - Capabilities
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
  *
@@ -71,11 +71,14 @@
 	unsigned int connect_supported:1;
 	unsigned int p2p_go_supported:1;
 	unsigned int p2p_client_supported:1;
+	unsigned int p2p_go_ctwindow_supported:1;
 	unsigned int p2p_concurrent:1;
 	unsigned int channel_switch_supported:1;
 	unsigned int set_qos_map_supported:1;
 	unsigned int have_low_prio_scan:1;
 	unsigned int wmm_ac_supported:1;
+	unsigned int mac_addr_rand_scan_supported:1;
+	unsigned int mac_addr_rand_sched_scan_supported:1;
 };
 
 
@@ -332,6 +335,33 @@
 }
 
 
+static int ext_feature_isset(const u8 *ext_features, int ext_features_len,
+			     enum nl80211_ext_feature_index ftidx)
+{
+	u8 ft_byte;
+
+	if ((int) ftidx / 8 >= ext_features_len)
+		return 0;
+
+	ft_byte = ext_features[ftidx / 8];
+	return (ft_byte & BIT(ftidx % 8)) != 0;
+}
+
+
+static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
+					 struct nlattr *tb)
+{
+	struct wpa_driver_capa *capa = info->capa;
+
+	if (tb == NULL)
+		return;
+
+	if (ext_feature_isset(nla_data(tb), nla_len(tb),
+			      NL80211_EXT_FEATURE_VHT_IBSS))
+		capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+}
+
+
 static void wiphy_info_feature_flags(struct wiphy_info_data *info,
 				     struct nlattr *tb)
 {
@@ -358,9 +388,23 @@
 	if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
 		capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
 
+	if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
+	}
+
+	if (flags & NL80211_FEATURE_P2P_GO_CTWIN)
+		info->p2p_go_ctwindow_supported = 1;
+
 	if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
 		info->have_low_prio_scan = 1;
 
+	if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
+		info->mac_addr_rand_scan_supported = 1;
+
+	if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
+		info->mac_addr_rand_sched_scan_supported = 1;
+
 	if (flags & NL80211_FEATURE_STATIC_SMPS)
 		capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
 
@@ -381,6 +425,9 @@
 
 	if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
 		capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
+
+	if (flags & NL80211_FEATURE_HT_IBSS)
+		capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
 }
 
 
@@ -489,6 +536,7 @@
 		info->device_ap_sme = 1;
 
 	wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+	wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
 	wiphy_info_probe_resp_offload(capa,
 				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
 
@@ -504,11 +552,11 @@
 				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
 		}
 		drv->extended_capa_mask =
-			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
 		if (drv->extended_capa_mask) {
 			os_memcpy(drv->extended_capa_mask,
-				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
-				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
 		} else {
 			os_free(drv->extended_capa);
 			drv->extended_capa = NULL;
@@ -527,19 +575,25 @@
 				continue;
 			}
 			vinfo = nla_data(nl);
-			switch (vinfo->subcmd) {
-			case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
-				drv->roaming_vendor_cmd_avail = 1;
-				break;
-			case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
-				drv->dfs_vendor_cmd_avail = 1;
-				break;
-			case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
-				drv->get_features_vendor_cmd_avail = 1;
-				break;
-			case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
-				drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
-				break;
+			if (vinfo->vendor_id == OUI_QCA) {
+				switch (vinfo->subcmd) {
+				case QCA_NL80211_VENDOR_SUBCMD_TEST:
+					drv->vendor_cmd_test_avail = 1;
+					break;
+				case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+					drv->roaming_vendor_cmd_avail = 1;
+					break;
+				case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+					drv->dfs_vendor_cmd_avail = 1;
+					break;
+				case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+					drv->get_features_vendor_cmd_avail = 1;
+					break;
+				case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+					drv->capa.flags |=
+						WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+					break;
+				}
 			}
 
 			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
@@ -630,6 +684,11 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
 	drv->capa.wmm_ac_supported = info->wmm_ac_supported;
 
+	drv->capa.mac_addr_rand_sched_scan_supported =
+		info->mac_addr_rand_sched_scan_supported;
+	drv->capa.mac_addr_rand_scan_supported =
+		info->mac_addr_rand_scan_supported;
+
 	return 0;
 }
 
@@ -770,7 +829,9 @@
 	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
 		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
+		WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
 	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
@@ -801,6 +862,7 @@
 	drv->device_ap_sme = info.device_ap_sme;
 	drv->poll_command_supported = info.poll_command_supported;
 	drv->data_tx_status = info.data_tx_status;
+	drv->p2p_go_ctwindow_supported = info.p2p_go_ctwindow_supported;
 	if (info.set_qos_map_supported)
 		drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
 	drv->have_low_prio_scan = info.have_low_prio_scan;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 85769d8..8cebfb2 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -180,34 +180,23 @@
 }
 
 
-static int nl80211_parse_wmm_params(struct nlattr *wmm_attr,
-				    struct wmm_params *wmm_params)
+static void nl80211_parse_wmm_params(struct nlattr *wmm_attr,
+				     struct wmm_params *wmm_params)
 {
 	struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1];
 	static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = {
 		[NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
 	};
 
-	if (!wmm_attr) {
-		wpa_printf(MSG_DEBUG, "nl80211: WMM data missing");
-		return -1;
-	}
-
-	if (nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
-			     wme_policy)) {
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Failed to parse nested attributes");
-		return -1;
-	}
-
-	if (!wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
-		return -1;
+	if (!wmm_attr ||
+	    nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+			     wme_policy) ||
+	    !wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+		return;
 
 	wmm_params->uapsd_queues =
 		nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
 	wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
-
-	return 0;
 }
 
 
@@ -282,6 +271,7 @@
 			       struct nlattr *ptk_kek)
 {
 	union wpa_event_data event;
+	const u8 *ssid;
 	u16 status_code;
 
 	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
@@ -342,6 +332,16 @@
 	if (req_ie) {
 		event.assoc_info.req_ies = nla_data(req_ie);
 		event.assoc_info.req_ies_len = nla_len(req_ie);
+
+		if (cmd == NL80211_CMD_ROAM) {
+			ssid = nl80211_get_ie(event.assoc_info.req_ies,
+					      event.assoc_info.req_ies_len,
+					      WLAN_EID_SSID);
+			if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
+				drv->ssid_len = ssid[1];
+				os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+			}
+		}
 	}
 	if (resp_ie) {
 		event.assoc_info.resp_ies = nla_data(resp_ie);
@@ -1104,10 +1104,8 @@
 	const u8 *addr;
 	union wpa_event_data data;
 
-	if (drv->nlmode != NL80211_IFTYPE_MESH_POINT)
-		return;
-
-	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+	if (drv->nlmode != NL80211_IFTYPE_MESH_POINT ||
+	    !tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
 		return;
 
 	addr = nla_data(tb[NL80211_ATTR_MAC]);
@@ -1201,14 +1199,11 @@
 	};
 	union wpa_event_data data;
 
-	if (!tb[NL80211_ATTR_MAC])
-		return;
-	if (!tb[NL80211_ATTR_REKEY_DATA])
-		return;
-	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
-			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
-		return;
-	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+	if (!tb[NL80211_ATTR_MAC] ||
+	    !tb[NL80211_ATTR_REKEY_DATA] ||
+	    nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy) ||
+	    !rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
 		return;
 
 	os_memset(&data, 0, sizeof(data));
@@ -1239,12 +1234,10 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
 
-	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
-		return;
-	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
-			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
-		return;
-	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE] ||
+	    nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy) ||
+	    !cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
 	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
 		return;
 
@@ -1300,6 +1293,12 @@
 			   MACSTR, MAC2STR(data.tdls.peer));
 		data.tdls.oper = TDLS_REQUEST_TEARDOWN;
 		break;
+	case NL80211_TDLS_DISCOVERY_REQ:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TDLS discovery request for peer " MACSTR,
+			   MAC2STR(data.tdls.peer));
+		data.tdls.oper = TDLS_REQUEST_DISCOVER;
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
 			   "event");
@@ -1502,10 +1501,8 @@
 		   "nl80211: ACS channel selection vendor event received");
 
 	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
-		      (struct nlattr *) data, len, NULL))
-		return;
-
-	if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+		      (struct nlattr *) data, len, NULL) ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
 	    !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
 		return;
 
@@ -1514,6 +1511,25 @@
 		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
 	event.acs_selected_channels.sec_channel =
 		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+		event.acs_selected_channels.vht_seg0_center_ch =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+		event.acs_selected_channels.vht_seg1_center_ch =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+		event.acs_selected_channels.ch_width =
+			nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
+
+	wpa_printf(MSG_INFO,
+		   "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d",
+		   event.acs_selected_channels.pri_channel,
+		   event.acs_selected_channels.sec_channel,
+		   event.acs_selected_channels.ch_width,
+		   event.acs_selected_channels.vht_seg0_center_ch,
+		   event.acs_selected_channels.vht_seg1_center_ch);
+
+	/* Ignore ACS channel list check for backwards compatibility */
 
 	wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
 }
@@ -1529,9 +1545,8 @@
 		   "nl80211: Key management roam+auth vendor event received");
 
 	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX,
-		      (struct nlattr *) data, len, NULL))
-		return;
-	if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
+		      (struct nlattr *) data, len, NULL) ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
 	    nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN ||
 	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] ||
 	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] ||
@@ -1552,10 +1567,99 @@
 }
 
 
+static void qca_nl80211_dfs_offload_radar_event(
+	struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
+{
+	union wpa_event_data data;
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: DFS offload radar vendor event received");
+
+	if (nla_parse(tb, NL80211_ATTR_MAX,
+		      (struct nlattr *) msg, length, NULL))
+		return;
+
+	if (!tb[NL80211_ATTR_WIPHY_FREQ]) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event");
+		return;
+	}
+
+	os_memset(&data, 0, sizeof(data));
+	data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+		   data.dfs_event.freq);
+
+	/* Check HT params */
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		data.dfs_event.ht_enabled = 1;
+		data.dfs_event.chan_offset = 0;
+
+		switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+		case NL80211_CHAN_NO_HT:
+			data.dfs_event.ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			data.dfs_event.chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			data.dfs_event.chan_offset = -1;
+			break;
+		}
+	}
+
+	/* Get VHT params */
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+		data.dfs_event.chan_width =
+			convert2width(nla_get_u32(
+					      tb[NL80211_ATTR_CHANNEL_WIDTH]));
+	if (tb[NL80211_ATTR_CENTER_FREQ1])
+		data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+	if (tb[NL80211_ATTR_CENTER_FREQ2])
+		data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, "
+		    "offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+		    data.dfs_event.freq, data.dfs_event.ht_enabled,
+		    data.dfs_event.chan_offset, data.dfs_event.chan_width,
+		    data.dfs_event.cf1, data.dfs_event.cf2);
+
+	switch (subcmd) {
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Unknown DFS offload radar event %d received",
+			   subcmd);
+		break;
+	}
+}
+
+
 static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
 				     u32 subcmd, u8 *data, size_t len)
 {
 	switch (subcmd) {
+	case QCA_NL80211_VENDOR_SUBCMD_TEST:
+		wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len);
+		break;
 	case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
 		qca_nl80211_avoid_freq(drv, data, len);
 		break;
@@ -1565,6 +1669,13 @@
 	case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
 		qca_nl80211_acs_select_ch(drv, data, len);
 		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+	case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+		qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Ignore unsupported QCA vendor event %u",
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 89f2279..9cd3162 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -171,6 +171,28 @@
 		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
 	}
 
+	if (params->mac_addr_rand) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+		scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+		if (params->mac_addr) {
+			wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+				   MAC2STR(params->mac_addr));
+			if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+				    params->mac_addr))
+				goto fail;
+		}
+
+		if (params->mac_addr_mask) {
+			wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+				   MACSTR, MAC2STR(params->mac_addr_mask));
+			if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
+				    params->mac_addr_mask))
+				goto fail;
+		}
+	}
+
 	if (scan_flags &&
 	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
 		goto fail;
@@ -244,7 +266,7 @@
 				goto fail;
 
 			if (wpa_driver_nl80211_scan(bss, params)) {
-				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
+				wpa_driver_nl80211_set_mode(bss, old_mode);
 				goto fail;
 			}
 
@@ -411,7 +433,7 @@
 }
 
 
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
 {
 	const u8 *end, *pos;
 
@@ -577,9 +599,6 @@
 		enum nl80211_bss_status status;
 		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
 		switch (status) {
-		case NL80211_BSS_STATUS_AUTHENTICATED:
-			r->flags |= WPA_SCAN_AUTHENTICATED;
-			break;
 		case NL80211_BSS_STATUS_ASSOCIATED:
 			r->flags |= WPA_SCAN_ASSOCIATED;
 			break;
@@ -655,23 +674,6 @@
 
 	for (i = 0; i < res->num; i++) {
 		struct wpa_scan_res *r = res->res[i];
-		if (r->flags & WPA_SCAN_AUTHENTICATED) {
-			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-				   "indicates BSS status with " MACSTR
-				   " as authenticated",
-				   MAC2STR(r->bssid));
-			if (is_sta_interface(drv->nlmode) &&
-			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
-			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
-			    0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
-					   " in local state (auth=" MACSTR
-					   " assoc=" MACSTR ")",
-					   MAC2STR(drv->auth_bssid),
-					   MAC2STR(drv->bssid));
-				clear_state_mismatch(drv, r->bssid);
-			}
-		}
 
 		if (r->flags & WPA_SCAN_ASSOCIATED) {
 			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
@@ -764,9 +766,8 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
 	for (i = 0; i < res->num; i++) {
 		struct wpa_scan_res *r = res->res[i];
-		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
+		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
 			   (int) i, (int) res->num, MAC2STR(r->bssid),
-			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
 			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
 	}
 
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index de23fbd..26d2bab 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -281,14 +281,15 @@
 {
 	struct wpa_driver_privsep_data *drv = priv;
 	int res, ssid_len;
-	u8 reply[sizeof(int) + 32];
+	u8 reply[sizeof(int) + SSID_MAX_LEN];
 	size_t len = sizeof(reply);
 
 	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
 	if (res < 0 || len < sizeof(int))
 		return -1;
 	os_memcpy(&ssid_len, reply, sizeof(int));
-	if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+	if (ssid_len < 0 || ssid_len > SSID_MAX_LEN ||
+	    sizeof(int) + ssid_len > len) {
 		wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
 		return -1;
 	}
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index a1581b8..01defdf 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,6 +18,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <net/if_arp.h>
+#include <dirent.h>
 
 #include "linux_wext.h"
 #include "common.h"
@@ -131,7 +132,7 @@
 	os_memset(&iwr, 0, sizeof(iwr));
 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.essid.pointer = (caddr_t) ssid;
-	iwr.u.essid.length = 32;
+	iwr.u.essid.length = SSID_MAX_LEN;
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
@@ -139,8 +140,8 @@
 		ret = -1;
 	} else {
 		ret = iwr.u.essid.length;
-		if (ret > 32)
-			ret = 32;
+		if (ret > SSID_MAX_LEN)
+			ret = SSID_MAX_LEN;
 		/* Some drivers include nul termination in the SSID, so let's
 		 * remove it here before further processing. WE-21 changes this
 		 * to explicitly require the length _not_ to include nul
@@ -168,7 +169,7 @@
 	int ret = 0;
 	char buf[33];
 
-	if (ssid_len > 32)
+	if (ssid_len > SSID_MAX_LEN)
 		return -1;
 
 	os_memset(&iwr, 0, sizeof(iwr));
@@ -874,6 +875,105 @@
 }
 
 
+static int wext_hostap_ifname(struct wpa_driver_wext_data *drv,
+			      const char *ifname)
+{
+	char buf[200], *res;
+	int type;
+	FILE *f;
+
+	if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
+		return -1;
+
+	snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+		 drv->ifname, ifname);
+
+	f = fopen(buf, "r");
+	if (!f)
+		return -1;
+	res = fgets(buf, sizeof(buf), f);
+	fclose(f);
+
+	type = res ? atoi(res) : -1;
+	wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type);
+
+	if (type == ARPHRD_IEEE80211) {
+		wpa_printf(MSG_DEBUG,
+			   "WEXT: Found hostap driver wifi# interface (%s)",
+			   ifname);
+		wpa_driver_wext_alternative_ifindex(drv, ifname);
+		return 0;
+	}
+	return -1;
+}
+
+
+static int wext_add_hostap(struct wpa_driver_wext_data *drv)
+{
+	char buf[200];
+	int n;
+	struct dirent **names;
+	int ret = -1;
+
+	snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname);
+	n = scandir(buf, &names, NULL, alphasort);
+	if (n < 0)
+		return -1;
+
+	while (n--) {
+		if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0)
+			ret = 0;
+		free(names[n]);
+	}
+	free(names);
+
+	return ret;
+}
+
+
+static void wext_check_hostap(struct wpa_driver_wext_data *drv)
+{
+	char buf[200], *pos;
+	ssize_t res;
+
+	/*
+	 * Host AP driver may use both wlan# and wifi# interface in wireless
+	 * events. Since some of the versions included WE-18 support, let's add
+	 * the alternative ifindex also from driver_wext.c for the time being.
+	 * This may be removed at some point once it is believed that old
+	 * versions of the driver are not in use anymore. However, it looks like
+	 * the wifi# interface is still used in the current kernel tree, so it
+	 * may not really be possible to remove this before the Host AP driver
+	 * gets removed from the kernel.
+	 */
+
+	/* First, try to see if driver information is available from sysfs */
+	snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
+		 drv->ifname);
+	res = readlink(buf, buf, sizeof(buf) - 1);
+	if (res > 0) {
+		buf[res] = '\0';
+		pos = strrchr(buf, '/');
+		if (pos)
+			pos++;
+		else
+			pos = buf;
+		wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos);
+		if (os_strncmp(pos, "hostap", 6) == 0 &&
+		    wext_add_hostap(drv) == 0)
+			return;
+	}
+
+	/* Second, use the old design with hardcoded ifname */
+	if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+		char ifname2[IFNAMSIZ + 1];
+		os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+		os_memcpy(ifname2, "wifi", 4);
+		wpa_driver_wext_alternative_ifindex(drv, ifname2);
+	}
+}
+
+
 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
 {
 	int send_rfkill_event = 0;
@@ -914,20 +1014,7 @@
 
 	drv->ifindex = if_nametoindex(drv->ifname);
 
-	if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
-		/*
-		 * Host AP driver may use both wlan# and wifi# interface in
-		 * wireless events. Since some of the versions included WE-18
-		 * support, let's add the alternative ifindex also from
-		 * driver_wext.c for the time being. This may be removed at
-		 * some point once it is believed that old versions of the
-		 * driver are not in use anymore.
-		 */
-		char ifname2[IFNAMSIZ + 1];
-		os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
-		os_memcpy(ifname2, "wifi", 4);
-		wpa_driver_wext_alternative_ifindex(drv, ifname2);
-	}
+	wext_check_hostap(drv);
 
 	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
 			       1, IF_OPER_DORMANT);
@@ -1112,7 +1199,7 @@
 	struct wpa_scan_res res;
 	u8 *ie;
 	size_t ie_len;
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	int maxrate;
 };
@@ -1865,7 +1952,7 @@
 {
 	struct iwreq iwr;
 	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	int i;
 
 	/*
@@ -1907,9 +1994,9 @@
 		 * SIOCSIWMLME commands (or tries to associate automatically
 		 * after deauth/disassoc).
 		 */
-		for (i = 0; i < 32; i++)
+		for (i = 0; i < SSID_MAX_LEN; i++)
 			ssid[i] = rand() & 0xFF;
-		if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+		if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) {
 			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
 				   "SSID to disconnect");
 		}
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index ab392bc..9434078 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -39,7 +39,13 @@
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+  ifdef LIBNL_INC
+    DRV_CFLAGS += -I$(LIBNL_INC)
+  else
+    PKG_CONFIG ?= pkg-config
+    DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
+  endif
 ifdef CONFIG_LIBNL3_ROUTE
   DRV_LIBS += -lnl-route-3
   DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 9b3025e..ae16ba9 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -25,10 +25,30 @@
  *
  */
 
+/*
+ * This header file defines the userspace API to the wireless stack. Please
+ * be careful not to break things - i.e. don't move anything around or so
+ * unless you can demonstrate that it breaks neither API nor ABI.
+ *
+ * Additions to the API should be accompanied by actual implementations in
+ * an upstream driver, so that example implementations exist in case there
+ * are ever concerns about the precise semantics of the API or changes are
+ * needed, and to ensure that code for dead (no longer implemented) API
+ * can actually be identified and removed.
+ * Nonetheless, semantics should also be documented carefully in this file.
+ */
+
 #include <linux/types.h>
 
 #define NL80211_GENL_NAME "nl80211"
 
+#define NL80211_MULTICAST_GROUP_CONFIG		"config"
+#define NL80211_MULTICAST_GROUP_SCAN		"scan"
+#define NL80211_MULTICAST_GROUP_REG		"regulatory"
+#define NL80211_MULTICAST_GROUP_MLME		"mlme"
+#define NL80211_MULTICAST_GROUP_VENDOR		"vendor"
+#define NL80211_MULTICAST_GROUP_TESTMODE	"testmode"
+
 /**
  * DOC: Station handling
  *
@@ -173,8 +193,8 @@
  *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
  *
  * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
- *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
- *	on an %NL80211_ATTR_IFINDEX is supported.
+ *	either a dump request for all interfaces or a specific get with a
+ *	single %NL80211_ATTR_IFINDEX is supported.
  * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
  *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
  * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
@@ -252,7 +272,18 @@
  *	%NL80211_ATTR_IFINDEX.
  *
  * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
- * 	regulatory domain.
+ *	regulatory domain. If %NL80211_ATTR_WIPHY is specified and the device
+ *	has a private regulatory domain, it will be returned. Otherwise, the
+ *	global regdomain will be returned.
+ *	A device will have a private regulatory domain if it uses the
+ *	regulatory_hint() API. Even when a private regdomain is used the channel
+ *	information will still be mended according to further hints from
+ *	the regulatory core to help with compliance. A dump version of this API
+ *	is now available which will returns the global regdomain as well as
+ *	all private regdomains of present wiphys (for those that have it).
+ *	If a wiphy is self-managed (%NL80211_ATTR_WIPHY_SELF_MANAGED_REG), then
+ *	its private regdomain is the only valid one for it. The regulatory
+ *	core is not used to help with compliance in this case.
  * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
  *	after being queried by the kernel. CRDA replies by sending a regulatory
  *	domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
@@ -306,7 +337,9 @@
  *	if passed, define which channels should be scanned; if not
  *	passed, all channels allowed for the current regulatory domain
  *	are used.  Extra IEs can also be passed from the userspace by
- *	using the %NL80211_ATTR_IE attribute.
+ *	using the %NL80211_ATTR_IE attribute.  The first cycle of the
+ *	scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY
+ *	is supplied.
  * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
  *	scheduled scan is not running. The caller may assume that as soon
  *	as the call returns, it is safe to start a new scheduled scan again.
@@ -643,7 +676,18 @@
  * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
  *	independently of the userspace SME, send this event indicating
  *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
- *	attributes determining channel width.
+ *	attributes determining channel width.  This indication may also be
+ *	sent when a remotely-initiated switch (e.g., when a STA receives a CSA
+ *	from the remote AP) is completed;
+ *
+ * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch
+ *	has been started on an interface, regardless of the initiator
+ *	(ie. whether it was requested from a remote device or
+ *	initiated on our own).  It indicates that
+ *	%NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ
+ *	after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's.  The userspace may
+ *	decide to react to this indication by requesting other
+ *	interfaces to change channel as well.
  *
  * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
  *	its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -751,6 +795,22 @@
  * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
  *	network is determined by the network interface.
  *
+ * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer,
+ *	identified by the %NL80211_ATTR_MAC parameter. A target channel is
+ *	provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining
+ *	channel width/type. The target operating class is given via
+ *	%NL80211_ATTR_OPER_CLASS.
+ *	The driver is responsible for continually initiating channel-switching
+ *	operations and returning to the base channel for communication with the
+ *	AP.
+ * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS
+ *	peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
+ *	when this command completes.
+ *
+ * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
+ *	as an event to indicate changes for devices with wiphy-specific regdom
+ *	management.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -930,6 +990,13 @@
 	NL80211_CMD_JOIN_OCB,
 	NL80211_CMD_LEAVE_OCB,
 
+	NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
+
+	NL80211_CMD_TDLS_CHANNEL_SWITCH,
+	NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+
+	NL80211_CMD_WIPHY_REG_CHANGE,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1624,9 +1691,16 @@
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  *	As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  *	creation then the new interface will be owned by the netlink socket
- *	that created it and will be destroyed when the socket is closed
+ *	that created it and will be destroyed when the socket is closed.
+ *	If set during scheduled scan start then the new scan req will be
+ *	owned by the netlink socket that created it and the scheduled scan will
+ *	be stopped when the socket is closed.
+ *	If set during configuration of regulatory indoor operation then the
+ *	regulatory indoor configuration would be owned by the netlink socket
+ *	that configured the indoor setting, and the indoor operation would be
+ *	cleared when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
@@ -1656,6 +1730,37 @@
  * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
  *	&enum nl80211_smps_mode.
  *
+ * @NL80211_ATTR_OPER_CLASS: operating class
+ *
+ * @NL80211_ATTR_MAC_MASK: MAC address mask
+ *
+ * @NL80211_ATTR_WIPHY_SELF_MANAGED_REG: flag attribute indicating this device
+ *	is self-managing its regulatory information and any regulatory domain
+ *	obtained from it is coming from the device's wiphy and not the global
+ *	cfg80211 regdomain.
+ *
+ * @NL80211_ATTR_EXT_FEATURES: extended feature flags contained in a byte
+ *	array. The feature flags are identified by their bit index (see &enum
+ *	nl80211_ext_feature_index). The bit index is ordered starting at the
+ *	least-significant bit of the first byte in the array, ie. bit index 0
+ *	is located at bit 0 of byte 0. bit index 25 would be located at bit 1
+ *	of byte 3 (u8 array).
+ *
+ * @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be
+ *	returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY
+ *	may return a survey entry without a channel indicating global radio
+ *	statistics (only some values are valid and make sense.)
+ *	For devices that don't return such an entry even then, the information
+ *	should be contained in the result as the sum of the respective counters
+ *	over all channels.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
+ *	WoWLAN net-detect scan) is started, u32 in seconds.
+
+ * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
+ *      is operating in an indoor environment.
+ *
+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1991,7 +2096,7 @@
 
 	NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-	NL80211_ATTR_IFACE_SOCKET_OWNER,
+	NL80211_ATTR_SOCKET_OWNER,
 
 	NL80211_ATTR_CSA_C_OFFSETS_TX,
 	NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2008,15 +2113,33 @@
 
 	NL80211_ATTR_SMPS_MODE,
 
+	NL80211_ATTR_OPER_CLASS,
+
+	NL80211_ATTR_MAC_MASK,
+
+	NL80211_ATTR_WIPHY_SELF_MANAGED_REG,
+
+	NL80211_ATTR_EXT_FEATURES,
+
+	NL80211_ATTR_SURVEY_RADIO_STATS,
+
+	NL80211_ATTR_NETNS_FD,
+
+	NL80211_ATTR_SCHED_SCAN_DELAY,
+
+	NL80211_ATTR_REG_INDOOR,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
+	NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
 #define	NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
@@ -2046,7 +2169,7 @@
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_HT_RATES		77
-#define NL80211_MAX_SUPP_REG_RULES		32
+#define NL80211_MAX_SUPP_REG_RULES		64
 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY	0
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY	16
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
@@ -2186,8 +2309,15 @@
  * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
  * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
  * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
- * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: unused - 80+80 is treated the
+ *	same as 160 for purposes of the bitrates
  * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
+ * @NL80211_RATE_INFO_10_MHZ_WIDTH: 10 MHz width - note that this is
+ *	a legacy rate and will be reported as the actual bitrate, i.e.
+ *	half the base (20 MHz) rate
+ * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
+ *	a legacy rate and will be reported as the actual bitrate, i.e.
+ *	a quarter of the base (20 MHz) rate
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -2202,6 +2332,8 @@
 	NL80211_RATE_INFO_80_MHZ_WIDTH,
 	NL80211_RATE_INFO_80P80_MHZ_WIDTH,
 	NL80211_RATE_INFO_160_MHZ_WIDTH,
+	NL80211_RATE_INFO_10_MHZ_WIDTH,
+	NL80211_RATE_INFO_5_MHZ_WIDTH,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
@@ -2246,18 +2378,24 @@
  *
  * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
- * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (MPDU length)
+ *	(u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (MPDU length)
+ *	(u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (MPDU length)
+ *	(u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (MPDU length)
+ *	(u64, to this station)
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  * 	containing info as possible, see &enum nl80211_rate_info
- * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
- * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
- *	station)
- * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
- * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs)
+ *	(u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs)
+ *	(u32, to this station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (MPDUs) (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (MPDUs)
+ *	(u32, to this station)
  * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
  * @NL80211_STA_INFO_LLID: the station's mesh LLID
  * @NL80211_STA_INFO_PLID: the station's mesh PLID
@@ -2281,6 +2419,16 @@
  *	Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
  * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
  *	802.11 header (u32, kbps)
+ * @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons
+ *	(u64)
+ * @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64)
+ * @NL80211_STA_INFO_BEACON_SIGNAL_AVG: signal strength average
+ *	for beacons only (u8, dBm)
+ * @NL80211_STA_INFO_TID_STATS: per-TID statistics (see &enum nl80211_tid_stats)
+ *	This is a nested attribute where each the inner attribute number is the
+ *	TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
+ *	each one of those is again nested with &enum nl80211_tid_stats
+ *	attributes carrying the actual values.
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2313,6 +2461,10 @@
 	NL80211_STA_INFO_CHAIN_SIGNAL,
 	NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
 	NL80211_STA_INFO_EXPECTED_THROUGHPUT,
+	NL80211_STA_INFO_RX_DROP_MISC,
+	NL80211_STA_INFO_BEACON_RX,
+	NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+	NL80211_STA_INFO_TID_STATS,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -2320,6 +2472,31 @@
 };
 
 /**
+ * enum nl80211_tid_stats - per TID statistics attributes
+ * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_TID_STATS_RX_MSDU: number of MSDUs received (u64)
+ * @NL80211_TID_STATS_TX_MSDU: number of MSDUs transmitted (or
+ *	attempted to transmit; u64)
+ * @NL80211_TID_STATS_TX_MSDU_RETRIES: number of retries for
+ *	transmitted MSDUs (not counting the first attempt; u64)
+ * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
+ *	MSDUs (u64)
+ * @NUM_NL80211_TID_STATS: number of attributes here
+ * @NL80211_TID_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_tid_stats {
+	__NL80211_TID_STATS_INVALID,
+	NL80211_TID_STATS_RX_MSDU,
+	NL80211_TID_STATS_TX_MSDU,
+	NL80211_TID_STATS_TX_MSDU_RETRIES,
+	NL80211_TID_STATS_TX_MSDU_FAILED,
+
+	/* keep last */
+	NUM_NL80211_TID_STATS,
+	NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1
+};
+
+/**
  * enum nl80211_mpath_flags - nl80211 mesh path flags
  *
  * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -2652,6 +2829,11 @@
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *	base on contiguous rules and wider channels will be allowed to cross
  *	multiple contiguous/overlapping frequency ranges.
+ * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
+ * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
+ * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
+ * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
  */
 enum nl80211_reg_rule_flags {
 	NL80211_RRF_NO_OFDM		= 1<<0,
@@ -2664,11 +2846,18 @@
 	NL80211_RRF_NO_IR		= 1<<7,
 	__NL80211_RRF_NO_IBSS		= 1<<8,
 	NL80211_RRF_AUTO_BW		= 1<<11,
+	NL80211_RRF_GO_CONCURRENT	= 1<<12,
+	NL80211_RRF_NO_HT40MINUS	= 1<<13,
+	NL80211_RRF_NO_HT40PLUS		= 1<<14,
+	NL80211_RRF_NO_80MHZ		= 1<<15,
+	NL80211_RRF_NO_160MHZ		= 1<<16,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN	NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IBSS		NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IR		NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_HT40		(NL80211_RRF_NO_HT40MINUS |\
+					 NL80211_RRF_NO_HT40PLUS)
 
 /* For backport compatibility with older userspace */
 #define NL80211_RRF_NO_IR_ALL		(NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -2721,16 +2910,18 @@
  * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
  * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
- * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
- *	spent on this channel
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
+ *	was turned on (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary
  *	channel was sensed busy (either due to activity or energy detect)
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
  *	channel was sensed busy
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
- *	receiving data
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
- *	transmitting data
+ * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
+ *	receiving data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
+ *	transmitting data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
+ *	(on this channel or globally)
  * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
  *	currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2740,17 +2931,25 @@
 	NL80211_SURVEY_INFO_FREQUENCY,
 	NL80211_SURVEY_INFO_NOISE,
 	NL80211_SURVEY_INFO_IN_USE,
-	NL80211_SURVEY_INFO_CHANNEL_TIME,
-	NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
-	NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
-	NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
-	NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+	NL80211_SURVEY_INFO_TIME,
+	NL80211_SURVEY_INFO_TIME_BUSY,
+	NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+	NL80211_SURVEY_INFO_TIME_RX,
+	NL80211_SURVEY_INFO_TIME_TX,
+	NL80211_SURVEY_INFO_TIME_SCAN,
 
 	/* keep last */
 	__NL80211_SURVEY_INFO_AFTER_LAST,
 	NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
 };
 
+/* keep old names for compatibility */
+#define NL80211_SURVEY_INFO_CHANNEL_TIME		NL80211_SURVEY_INFO_TIME
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY		NL80211_SURVEY_INFO_TIME_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY	NL80211_SURVEY_INFO_TIME_EXT_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX		NL80211_SURVEY_INFO_TIME_RX
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX		NL80211_SURVEY_INFO_TIME_TX
+
 /**
  * enum nl80211_mntr_flags - monitor configuration flags
  *
@@ -2915,7 +3114,8 @@
  *
  * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
  *	established peering with for longer than this time (in seconds), then
- *	remove it from the STA's list of peers.  Default is 30 minutes.
+ *	remove it from the STA's list of peers. You may set this to 0 to disable
+ *	the removal of the STA. Default is 30 minutes.
  *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
@@ -3187,6 +3387,9 @@
 /**
  * enum nl80211_bss_status - BSS "status"
  * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ *	Note that this is no longer used since cfg80211 no longer
+ *	keeps track of whether or not authentication was done with
+ *	a given BSS.
  * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
  * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
  *
@@ -3400,6 +3603,8 @@
  *	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_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
+ *	loss event
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3412,6 +3617,7 @@
 	NL80211_ATTR_CQM_TXE_RATE,
 	NL80211_ATTR_CQM_TXE_PKTS,
 	NL80211_ATTR_CQM_TXE_INTVL,
+	NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
@@ -3424,9 +3630,7 @@
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
- * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
- *	(Note that deauth/disassoc will still follow if the AP is not
- *	available. This event might get used as roaming event, etc.)
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
  */
 enum nl80211_cqm_rssi_threshold_event {
 	NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
@@ -3513,6 +3717,8 @@
  * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
  *	the chip into a special state -- works best with chips that have
  *	support for low-power operation already (flag)
+ *	Note that this mode is incompatible with all of the others, if
+ *	any others are even supported by the device.
  * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
  *	is detected is implementation-specific (flag)
  * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
@@ -3566,6 +3772,28 @@
  * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
  *	the TCP connection ran out of tokens to use for data to send to the
  *	service
+ * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network
+ *	is detected.  This is a nested attribute that contains the
+ *	same attributes used with @NL80211_CMD_START_SCHED_SCAN.  It
+ *	specifies how the scan is performed (e.g. the interval, the
+ *	channels to scan and the initial delay) as well as the scan
+ *	results that will trigger a wake (i.e. the matchsets).  This
+ *	attribute is also sent in a response to
+ *	@NL80211_CMD_GET_WIPHY, indicating the number of match sets
+ *	supported by the driver (u32).
+ * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
+ *	containing an array with information about what triggered the
+ *	wake up.  If no elements are present in the array, it means
+ *	that the information is not available.  If more than one
+ *	element is present, it means that more than one match
+ *	occurred.
+ *	Each element in the array is a nested attribute that contains
+ *	one optional %NL80211_ATTR_SSID attribute and one optional
+ *	%NL80211_ATTR_SCAN_FREQUENCIES attribute.  At least one of
+ *	these attributes must be present.  If
+ *	%NL80211_ATTR_SCAN_FREQUENCIES contains more than one
+ *	frequency, it means that the match occurred in more than one
+ *	channel.
  * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
  * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
  *
@@ -3591,6 +3819,8 @@
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
+	NL80211_WOWLAN_TRIG_NET_DETECT,
+	NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS,
 
 	/* keep last */
 	NUM_NL80211_WOWLAN_TRIG,
@@ -4070,6 +4300,20 @@
  * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
  *	the vif's MAC address upon creation.
  *	See 'macaddr' field in the vif_params (cfg80211.h).
+ * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
+ *	operating as a TDLS peer.
+ * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
+ *	random MAC address during scan (if the device is unassociated); the
+ *	%NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
+ *	address mask/value will be used.
+ * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
+ *	using a random MAC address for every scan iteration during scheduled
+ *	scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ *	be set for scheduled scan and the MAC address mask/value will be used.
+ * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
+ *	random MAC address for every scan iteration during "net detect", i.e.
+ *	scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ *	be set for scheduled scan and the MAC address mask/value will be used.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -4100,6 +4344,25 @@
 	NL80211_FEATURE_DYNAMIC_SMPS			= 1 << 25,
 	NL80211_FEATURE_SUPPORTS_WMM_ADMISSION		= 1 << 26,
 	NL80211_FEATURE_MAC_ON_CREATE			= 1 << 27,
+	NL80211_FEATURE_TDLS_CHANNEL_SWITCH		= 1 << 28,
+	NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR		= 1 << 29,
+	NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR	= 1 << 30,
+	NL80211_FEATURE_ND_RANDOM_MAC_ADDR		= 1 << 31,
+};
+
+/**
+ * enum nl80211_ext_feature_index - bit index of extended features.
+ * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
+ *
+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+ */
+enum nl80211_ext_feature_index {
+	NL80211_EXT_FEATURE_VHT_IBSS,
+
+	/* add new features before the definition below */
+	NUM_NL80211_EXT_FEATURES,
+	MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
 };
 
 /**
@@ -4148,11 +4411,21 @@
  *	dangerous because will destroy stations performance as a lot of frames
  *	will be lost while scanning off-channel, therefore it must be used only
  *	when really needed
+ * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
+ *	for scheduled scan: a different one for every scan iteration). When the
+ *	flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
+ *	@NL80211_ATTR_MAC_MASK attributes may also be given in which case only
+ *	the masked bits will be preserved from the MAC address and the remainder
+ *	randomised. If the attributes are not given full randomisation (46 bits,
+ *	locally administered 1, multicast 0) is assumed.
+ *	This flag must not be requested when the feature isn't supported, check
+ *	the nl80211 feature flags for the device.
  */
 enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
 	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
 	NL80211_SCAN_FLAG_AP				= 1<<2,
+	NL80211_SCAN_FLAG_RANDOM_ADDR			= 1<<3,
 };
 
 /**
diff --git a/src/eap_common/Makefile b/src/eap_common/Makefile
index adfd3df..f00b438 100644
--- a/src/eap_common/Makefile
+++ b/src/eap_common/Makefile
@@ -1,8 +1,31 @@
-all:
-	@echo Nothing to be made.
+all: libeap_common.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_common.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+LIB_OBJS= \
+	chap.o \
+	eap_common.o \
+	eap_eke_common.o \
+	eap_eke_common.o \
+	eap_fast_common.o \
+	eap_gpsk_common.o \
+	eap_ikev2_common.o \
+	eap_pax_common.o \
+	eap_peap_common.o \
+	eap_psk_common.o \
+	eap_pwd_common.o \
+	eap_sake_common.o \
+	eap_sim_common.o \
+	eap_wsc_common.o \
+	ikev2_common.o
+
+libeap_common.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index fceb1b0..151cc78 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -96,49 +96,18 @@
 u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
 			 const char *label, size_t len)
 {
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-	int block_size;
+	u8 *out;
 
-	block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
-	if (block_size < 0)
-		return NULL;
-
-	out = os_malloc(block_size + len);
+	out = os_malloc(len);
 	if (out == NULL)
 		return NULL;
 
-	if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
-	    == 0) {
-		os_memmove(out, out + block_size, len);
-		return out;
+	if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) {
+		os_free(out);
+		return NULL;
 	}
 
-	if (tls_connection_get_keys(ssl_ctx, conn, &keys))
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
-			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
-			     label, rnd, keys.client_random_len +
-			     keys.server_random_len, out, block_size + len))
-		goto fail;
-	os_free(rnd);
-	os_memmove(out, out + block_size, len);
 	return out;
-
-fail:
-	os_free(rnd);
-	os_free(out);
-	return NULL;
 }
 
 
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 631c363..4d27623 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -86,9 +86,10 @@
  * on the password and identities.
  */
 int compute_password_element(EAP_PWD_group *grp, u16 num,
-			     u8 *password, int password_len,
-			     u8 *id_server, int id_server_len,
-			     u8 *id_peer, int id_peer_len, u8 *token)
+			     const u8 *password, size_t password_len,
+			     const u8 *id_server, size_t id_server_len,
+			     const u8 *id_peer, size_t id_peer_len,
+			     const u8 *token)
 {
 	BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
 	struct crypto_hash *hash;
@@ -283,10 +284,10 @@
 }
 
 
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
-		 BIGNUM *peer_scalar, BIGNUM *server_scalar,
-		 u8 *confirm_peer, u8 *confirm_server,
-		 u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
+int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
+		 const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+		 const u8 *confirm_peer, const u8 *confirm_server,
+		 const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
 {
 	struct crypto_hash *hash;
 	u8 mk[SHA256_MAC_LEN], *cruft;
@@ -306,7 +307,7 @@
 		os_free(cruft);
 		return -1;
 	}
-	eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32));
+	eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
 	offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
 	os_memset(cruft, 0, BN_num_bytes(grp->prime));
 	BN_bn2bin(peer_scalar, cruft + offset);
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index c54c441..a0d717e 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -56,10 +56,15 @@
 } STRUCT_PACKED;
 
 /* common routines */
-int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
-			     int, u8 *);
-int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
-		 u8 *, u8 *, u32 *, u8 *, u8 *, u8 *);
+int compute_password_element(EAP_PWD_group *grp, u16 num,
+			     const u8 *password, size_t password_len,
+			     const u8 *id_server, size_t id_server_len,
+			     const u8 *id_peer, size_t id_peer_len,
+			     const u8 *token);
+int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
+		 const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+		 const u8 *confirm_peer, const u8 *confirm_server,
+		 const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
 struct crypto_hash * eap_pwd_h_init(void);
 void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
 void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
diff --git a/src/eap_peer/Makefile b/src/eap_peer/Makefile
index f79519b..6531ccd 100644
--- a/src/eap_peer/Makefile
+++ b/src/eap_peer/Makefile
@@ -1,11 +1,23 @@
-all:
-	@echo Nothing to be made.
+all: libeap_peer.a
 
 clean:
-	rm -f *~ *.o *.so *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.so *.d *.gcno *.gcda *.gcov libeap_peer.a
 
 install:
 	if ls *.so >/dev/null 2>&1; then \
 		install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
 		cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
 	; fi
+
+include ../lib.rules
+
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS= \
+	eap.o \
+	eap_methods.o
+
+libeap_peer.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 31c1a29..fc4af95 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -934,6 +934,15 @@
 }
 
 
+static int eap_peer_sm_allow_canned(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	return config && config->phase1 &&
+		os_strstr(config->phase1, "allow_canned_success=1");
+}
+
+
 static void eap_peer_sm_step_received(struct eap_sm *sm)
 {
 	int duplicate = eap_peer_req_is_duplicate(sm);
@@ -947,6 +956,17 @@
 	    (sm->reqId == sm->lastId ||
 	     eap_success_workaround(sm, sm->reqId, sm->lastId)))
 		SM_ENTER(EAP, SUCCESS);
+	else if (sm->workaround && sm->lastId == -1 && sm->rxSuccess &&
+		 !sm->rxFailure && !sm->rxReq && eap_peer_sm_allow_canned(sm))
+		SM_ENTER(EAP, SUCCESS); /* EAP-Success prior any EAP method */
+	else if (sm->workaround && sm->lastId == -1 && sm->rxFailure &&
+		 !sm->rxReq && sm->methodState != METHOD_CONT &&
+		 eap_peer_sm_allow_canned(sm))
+		SM_ENTER(EAP, FAILURE); /* EAP-Failure prior any EAP method */
+	else if (sm->workaround && sm->rxSuccess && !sm->rxFailure &&
+		 !sm->rxReq && sm->methodState != METHOD_CONT &&
+		 eap_peer_sm_allow_canned(sm))
+		SM_ENTER(EAP, SUCCESS); /* EAP-Success after Identity */
 	else if (sm->methodState != METHOD_CONT &&
 		 ((sm->rxFailure &&
 		   sm->decision != DECISION_UNCOND_SUCC) ||
@@ -1858,6 +1878,8 @@
 		sm->eapol_cb->notify_cert(sm->eapol_ctx,
 					  data->peer_cert.depth,
 					  data->peer_cert.subject,
+					  data->peer_cert.altsubject,
+					  data->peer_cert.num_altsubject,
 					  hash_hex, data->peer_cert.cert);
 		break;
 	case TLS_ALERT:
@@ -2378,7 +2400,7 @@
 u32 eap_get_phase2_type(const char *name, int *vendor)
 {
 	int v;
-	u8 type = eap_peer_get_type(name, &v);
+	u32 type = eap_peer_get_type(name, &v);
 	if (eap_allowed_phase2_type(v, type)) {
 		*vendor = v;
 		return type;
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index bc207e7..702463b 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -228,10 +228,13 @@
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
 	 * @depth: Depth in certificate chain (0 = server)
 	 * @subject: Subject of the peer certificate
+	 * @altsubject: Select fields from AltSubject of the peer certificate
+	 * @num_altsubject: Number of altsubject values
 	 * @cert_hash: SHA-256 hash of the certificate
 	 * @cert: Peer certificate
 	 */
 	void (*notify_cert)(void *ctx, int depth, const char *subject,
+			    const char *altsubject[], int num_altsubject,
 			    const char *cert_hash, const struct wpabuf *cert);
 
 	/**
@@ -243,6 +246,14 @@
 	void (*notify_status)(void *ctx, const char *status,
 			      const char *parameter);
 
+#ifdef CONFIG_EAP_PROXY
+	/**
+	 * eap_proxy_cb - Callback signifying any updates from eap_proxy
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 */
+	void (*eap_proxy_cb)(void *ctx);
+#endif /* CONFIG_EAP_PROXY */
+
 	/**
 	 * set_anon_id - Set or add anonymous identity
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 3584bdb..2b1a1d5 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -186,6 +186,10 @@
 	 * string is in following format:
 	 *
 	 * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
+	 *
+	 * Note: Since this is a substring match, this cannot be used securily
+	 * to do a suffix match against a possible domain name in the CN entry.
+	 * For such a use case, domain_suffix_match should be used instead.
 	 */
 	u8 *subject_match;
 
@@ -213,7 +217,7 @@
 	 * If set, this FQDN is used as a suffix match requirement for the
 	 * server certificate in SubjectAltName dNSName element(s). If a
 	 * matching dNSName is found, this constraint is met. If no dNSName
-	 * values are present, this constraint is matched against SubjetName CN
+	 * values are present, this constraint is matched against SubjectName CN
 	 * using same suffix match comparison. Suffix match here means that the
 	 * host/domain name is compared one label at a time starting from the
 	 * top-level domain and all the labels in domain_suffix_match shall be
@@ -226,6 +230,21 @@
 	char *domain_suffix_match;
 
 	/**
+	 * domain_match - Constraint for server domain name
+	 *
+	 * If set, this FQDN is used as a full match requirement for the
+	 * server certificate in SubjectAltName dNSName element(s). If a
+	 * matching dNSName is found, this constraint is met. If no dNSName
+	 * values are present, this constraint is matched against SubjectName CN
+	 * using same full match comparison. This behavior is similar to
+	 * domain_suffix_match, but has the requirement of a full match, i.e.,
+	 * no subdomains or wildcard matches are allowed. Case-insensitive
+	 * comparison is used, so "Example.com" matches "example.com", but would
+	 * not match "test.Example.com".
+	 */
+	char *domain_match;
+
+	/**
 	 * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
 	 *
 	 * This file can have one or more trusted CA certificates. If ca_cert2
@@ -329,6 +348,14 @@
 	char *domain_suffix_match2;
 
 	/**
+	 * domain_match2 - Constraint for server domain name
+	 *
+	 * This field is like domain_match, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	char *domain_match2;
+
+	/**
 	 * eap_methods - Allowed EAP methods
 	 *
 	 * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
@@ -391,6 +418,16 @@
 	 *
 	 * EAP-WSC (WPS) uses following options: pin=Device_Password and
 	 * uuid=Device_UUID
+	 *
+	 * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+	 * used to configure a mode that allows EAP-Success (and EAP-Failure)
+	 * without going through authentication step. Some switches use such
+	 * sequence when forcing the port to be authorized/unauthorized or as a
+	 * fallback option if the authentication server is unreachable. By
+	 * default, wpa_supplicant discards such frames to protect against
+	 * potential attacks by rogue devices, but this option can be used to
+	 * disable that protection for cases where the server/authenticator does
+	 * not need to be authenticated.
 	 */
 	char *phase1;
 
@@ -398,7 +435,9 @@
 	 * 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.
+	 * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can
+	 * be used to disable MSCHAPv2 password retry in authentication failure
+	 * cases.
 	 */
 	char *phase2;
 
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 430c501..9e486e7 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -472,6 +472,13 @@
 		pos += 2;
 		msg = pos;
 	}
+	if (data->prev_error == ERROR_AUTHENTICATION_FAILURE && retry &&
+	    config && config->phase2 &&
+	    os_strstr(config->phase2, "mschapv2_retry=0")) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-MSCHAPV2: mark password retry disabled based on local configuration");
+		retry = 0;
+	}
 	wpa_msg(sm->msg_ctx, MSG_WARNING,
 		"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
 		"%d)",
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 059bbee..f2b0926 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "crypto/sha256.h"
+#include "crypto/ms_funcs.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -25,6 +26,7 @@
 	size_t id_server_len;
 	u8 *password;
 	size_t password_len;
+	int password_hash;
 	u16 group_num;
 	EAP_PWD_group *grp;
 
@@ -86,8 +88,9 @@
 	const u8 *identity, *password;
 	size_t identity_len, password_len;
 	int fragment_size;
+	int pwhash;
 
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	if (password == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
 		return NULL;
@@ -129,6 +132,7 @@
 	}
 	os_memcpy(data->password, password, password_len);
 	data->password_len = password_len;
+	data->password_hash = pwhash;
 
 	data->out_frag_pos = data->in_frag_pos = 0;
 	data->inbuf = data->outbuf = NULL;
@@ -216,6 +220,10 @@
 			    const u8 *payload, size_t payload_len)
 {
 	struct eap_pwd_id *id;
+	const u8 *password;
+	size_t password_len;
+	u8 pwhashhash[16];
+	int res;
 
 	if (data->state != PWD_ID_Req) {
 		ret->ignore = TRUE;
@@ -231,6 +239,9 @@
 
 	id = (struct eap_pwd_id *) payload;
 	data->group_num = be_to_host16(id->group_num);
+	wpa_printf(MSG_DEBUG,
+		   "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
+		   data->group_num, id->random_function, id->prf, id->prep);
 	if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
 	    (id->prf != EAP_PWD_DEFAULT_PRF)) {
 		ret->ignore = TRUE;
@@ -238,6 +249,22 @@
 		return;
 	}
 
+	if (id->prep != EAP_PWD_PREP_NONE &&
+	    id->prep != EAP_PWD_PREP_MS) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
+			   id->prep);
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PWD: Unhashed password not available");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
 	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
 		   data->group_num);
 
@@ -260,12 +287,39 @@
 		return;
 	}
 
+	if (id->prep == EAP_PWD_PREP_MS) {
+		if (data->password_hash) {
+			res = hash_nt_password_hash(data->password, pwhashhash);
+		} else {
+			u8 pwhash[16];
+
+			res = nt_password_hash(data->password,
+					       data->password_len, pwhash);
+			if (res == 0)
+				res = hash_nt_password_hash(pwhash, pwhashhash);
+			os_memset(pwhash, 0, sizeof(pwhash));
+		}
+
+		if (res) {
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
+
+		password = pwhashhash;
+		password_len = sizeof(pwhashhash);
+	} else {
+		password = data->password;
+		password_len = data->password_len;
+	}
+
 	/* compute PWE */
-	if (compute_password_element(data->grp, data->group_num,
-				     data->password, data->password_len,
-				     data->id_server, data->id_server_len,
-				     data->id_peer, data->id_peer_len,
-				     id->token)) {
+	res = compute_password_element(data->grp, data->group_num,
+				       password, password_len,
+				       data->id_server, data->id_server_len,
+				       data->id_peer, data->id_peer_len,
+				       id->token);
+	os_memset(pwhashhash, 0, sizeof(pwhashhash));
+	if (res) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
 		eap_pwd_state(data, FAILURE);
 		return;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 3641a2c..15c1bac 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -91,6 +91,7 @@
 	params->subject_match = (char *) config->subject_match;
 	params->altsubject_match = (char *) config->altsubject_match;
 	params->suffix_match = config->domain_suffix_match;
+	params->domain_match = config->domain_match;
 	params->engine = config->engine;
 	params->engine_id = config->engine_id;
 	params->pin = config->pin;
@@ -113,6 +114,7 @@
 	params->subject_match = (char *) config->subject_match2;
 	params->altsubject_match = (char *) config->altsubject_match2;
 	params->suffix_match = config->domain_suffix_match2;
+	params->domain_match = config->domain_match2;
 	params->engine = config->engine2;
 	params->engine_id = config->engine2_id;
 	params->pin = config->pin2;
@@ -311,53 +313,19 @@
 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;
+	u8 *out;
 
 	out = os_malloc(len);
 	if (out == NULL)
 		return NULL;
 
-	/* First, try to use TLS library function for PRF, if available. */
-	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
-	    == 0)
-		return out;
+	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
+			       out, len)) {
+		os_free(out);
+		return NULL;
+	}
 
-#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
-	 * derive the key.
-	 */
-	if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
-			     label, rnd, keys.client_random_len +
-			     keys.server_random_len, out, len))
-		goto fail;
-
-	os_free(rnd);
 	return out;
-
-fail:
-#endif /* CONFIG_FIPS */
-	os_free(out);
-	os_free(rnd);
-	return NULL;
 }
 
 
@@ -1030,7 +998,7 @@
 {
 	char *start, *pos, *buf;
 	struct eap_method_type *methods = NULL, *_methods;
-	u8 method;
+	u32 method;
 	size_t num_methods = 0, prefix_len;
 
 	if (config == NULL || config->phase2 == NULL)
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 6fbc27b..b5c028b 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -995,6 +995,7 @@
 				 resp, out_data)) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
 			   "frame");
+		wpabuf_free(resp);
 		return -1;
 	}
 	wpabuf_free(resp);
diff --git a/src/eap_peer/eap_vendor_test.c b/src/eap_peer/eap_vendor_test.c
index 040d1e7..b61057e 100644
--- a/src/eap_peer/eap_vendor_test.c
+++ b/src/eap_peer/eap_vendor_test.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: Test method for vendor specific (expanded) EAP type
- * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,31 +14,36 @@
 
 #include "common.h"
 #include "eap_i.h"
-#ifdef TEST_PENDING_REQUEST
 #include "eloop.h"
-#endif /* TEST_PENDING_REQUEST */
 
 
 #define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
 #define EAP_VENDOR_TYPE 0xfcfbfaf9
 
 
-/* #define TEST_PENDING_REQUEST */
-
 struct eap_vendor_test_data {
 	enum { INIT, CONFIRM, SUCCESS } state;
 	int first_try;
+	int test_pending_req;
 };
 
 
 static void * eap_vendor_test_init(struct eap_sm *sm)
 {
 	struct eap_vendor_test_data *data;
+	const u8 *password;
+	size_t password_len;
+
 	data = os_zalloc(sizeof(*data));
 	if (data == NULL)
 		return NULL;
 	data->state = INIT;
 	data->first_try = 1;
+
+	password = eap_get_config_password(sm, &password_len);
+	data->test_pending_req = password && password_len == 7 &&
+		os_memcmp(password, "pending", 7) == 0;
+
 	return data;
 }
 
@@ -50,7 +55,6 @@
 }
 
 
-#ifdef TEST_PENDING_REQUEST
 static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
 {
 	struct eap_sm *sm = eloop_ctx;
@@ -58,7 +62,6 @@
 		   "request");
 	eap_notify_pending(sm);
 }
-#endif /* TEST_PENDING_REQUEST */
 
 
 static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
@@ -98,8 +101,7 @@
 	}
 
 	if (data->state == CONFIRM) {
-#ifdef TEST_PENDING_REQUEST
-		if (data->first_try) {
+		if (data->test_pending_req && data->first_try) {
 			data->first_try = 0;
 			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
 				   "pending request");
@@ -108,7 +110,6 @@
 					       NULL);
 			return NULL;
 		}
-#endif /* TEST_PENDING_REQUEST */
 	}
 
 	ret->ignore = FALSE;
diff --git a/src/eap_server/Makefile b/src/eap_server/Makefile
index adfd3df..1172b72 100644
--- a/src/eap_server/Makefile
+++ b/src/eap_server/Makefile
@@ -1,8 +1,21 @@
-all:
-	@echo Nothing to be made.
+all: libeap_server.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_server.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_HS20
+
+LIB_OBJS= \
+	eap_server.o \
+	eap_server_identity.o \
+	eap_server_methods.o
+
+libeap_server.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 9de6cb6..b825e18 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -149,5 +149,8 @@
 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
 void eap_server_clear_identity(struct eap_sm *sm);
+void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
+				   const u8 *username, size_t username_len,
+				   const u8 *challenge, const u8 *response);
 
 #endif /* EAP_H */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index bd919e5..693debe 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1979,3 +1979,25 @@
 	os_free(sm->identity);
 	sm->identity = NULL;
 }
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
+				   const u8 *username, size_t username_len,
+				   const u8 *challenge, const u8 *response)
+{
+	char hex_challenge[30], hex_response[90], user[100];
+
+	/* Print out Challenge and Response in format supported by asleap. */
+	if (username)
+		printf_encode(user, sizeof(user), username, username_len);
+	else
+		user[0] = '\0';
+	wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge),
+			     challenge, sizeof(challenge), ':');
+	wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24,
+			     ':');
+	wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s",
+		   source, user, hex_challenge, hex_response);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 56ac7f4..6745100 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -819,6 +819,9 @@
 	encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
 	wpabuf_free(plain);
 
+	if (!encr)
+		return -1;
+
 	if (data->ssl.tls_out && piggyback) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
 			   "(len=%d) with last Phase 1 Message (len=%d "
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 0209fad..9e9dc93 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -153,7 +153,7 @@
  * eap_server_get_name - Get EAP method name for the given EAP type
  * @vendor: EAP Vendor-Id (0 = IETF)
  * @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ * Returns: EAP method name, e.g., TLS, or "unknown" if not found
  *
  * This function maps EAP type numbers into EAP type names based on the list of
  * EAP methods included in the build.
@@ -167,5 +167,5 @@
 		if (m->vendor == vendor && m->method == type)
 			return m->name;
 	}
-	return NULL;
+	return "unknown";
 }
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 05848d2..98d74e0 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -360,6 +360,19 @@
 		}
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	{
+		u8 challenge[8];
+
+		if (challenge_hash(peer_challenge, data->auth_challenge,
+				   username, username_len, challenge) == 0) {
+			eap_server_mschap_rx_callback(sm, "EAP-MSCHAPV2",
+						      username, username_len,
+						      challenge, nt_response);
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (username_len != user_len ||
 	    os_memcmp(username, user, username_len) != 0) {
 		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 98d608b..3848f30 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -344,12 +344,14 @@
 	size_t mlen;
 
 	mlen = 6; /* Result TLV */
-	if (data->crypto_binding != NO_BINDING)
+	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+	    data->crypto_binding != NO_BINDING) {
 		mlen += 60; /* Cryptobinding TLV */
 #ifdef EAP_SERVER_TNC
-	if (data->soh_response)
-		mlen += wpabuf_len(data->soh_response);
+		if (data->soh_response)
+			mlen += wpabuf_len(data->soh_response);
 #endif /* EAP_SERVER_TNC */
+	}
 
 	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
 			    EAP_CODE_REQUEST, id);
@@ -537,15 +539,14 @@
 
 
 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
-				EapType eap_type)
+				int vendor, EapType eap_type)
 {
 	if (data->phase2_priv && data->phase2_method) {
 		data->phase2_method->reset(sm, data->phase2_priv);
 		data->phase2_method = NULL;
 		data->phase2_priv = NULL;
 	}
-	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
-							eap_type);
+	data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
 	if (!data->phase2_method)
 		return -1;
 
@@ -735,7 +736,7 @@
 	const u8 *soh_tlv = NULL;
 	size_t soh_tlv_len = 0;
 	int tlv_type, mandatory, tlv_len, vtlv_len;
-	u8 next_type;
+	u32 next_type;
 	u32 vendor_id;
 
 	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
@@ -850,8 +851,9 @@
 	eap_peap_state(data, PHASE2_METHOD);
 	next_type = sm->user->methods[0].method;
 	sm->user_eap_method_index = 1;
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
-	eap_peap_phase2_init(sm, data, next_type);
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
+		   sm->user->methods[0].vendor, next_type);
+	eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
 }
 #endif /* EAP_SERVER_TNC */
 
@@ -860,7 +862,8 @@
 					     struct eap_peap_data *data,
 					     struct wpabuf *in_data)
 {
-	u8 next_type = EAP_TYPE_NONE;
+	int next_vendor = EAP_VENDOR_IETF;
+	u32 next_type = EAP_TYPE_NONE;
 	const struct eap_hdr *hdr;
 	const u8 *pos;
 	size_t left;
@@ -892,17 +895,23 @@
 			    "allowed types", pos + 1, left - 1);
 		eap_sm_process_nak(sm, pos + 1, left - 1);
 		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index].method !=
-		    EAP_TYPE_NONE) {
+		    (sm->user->methods[sm->user_eap_method_index].vendor !=
+		     EAP_VENDOR_IETF ||
+		     sm->user->methods[sm->user_eap_method_index].method !=
+		     EAP_TYPE_NONE)) {
+			next_vendor = sm->user->methods[
+				sm->user_eap_method_index].vendor;
 			next_type = sm->user->methods[
 				sm->user_eap_method_index++].method;
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
-				   next_type);
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PEAP: try EAP vendor %d type 0x%x",
+				   next_vendor, next_type);
 		} else {
 			eap_peap_req_failure(sm, data);
+			next_vendor = EAP_VENDOR_IETF;
 			next_type = EAP_TYPE_NONE;
 		}
-		eap_peap_phase2_init(sm, data, next_type);
+		eap_peap_phase2_init(sm, data, next_vendor, next_type);
 		return;
 	}
 
@@ -927,8 +936,9 @@
 	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
 		eap_peap_req_failure(sm, data);
+		next_vendor = EAP_VENDOR_IETF;
 		next_type = EAP_TYPE_NONE;
-		eap_peap_phase2_init(sm, data, next_type);
+		eap_peap_phase2_init(sm, data, next_vendor, next_type);
 		return;
 	}
 
@@ -940,7 +950,8 @@
 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
 				   "failed");
 			eap_peap_req_failure(sm, data);
-			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+			eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+					     EAP_TYPE_NONE);
 			return;
 		}
 	}
@@ -955,6 +966,7 @@
 					  "database",
 					  sm->identity, sm->identity_len);
 			eap_peap_req_failure(sm, data);
+			next_vendor = EAP_VENDOR_IETF;
 			next_type = EAP_TYPE_NONE;
 			break;
 		}
@@ -965,18 +977,22 @@
 			eap_peap_state(data, PHASE2_SOH);
 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
 				   "TNC (NAP SOH)");
+			next_vendor = EAP_VENDOR_IETF;
 			next_type = EAP_TYPE_NONE;
 			break;
 		}
 #endif /* EAP_SERVER_TNC */
 
 		eap_peap_state(data, PHASE2_METHOD);
+		next_vendor = sm->user->methods[0].vendor;
 		next_type = sm->user->methods[0].method;
 		sm->user_eap_method_index = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
+			   next_vendor, next_type);
 		break;
 	case PHASE2_METHOD:
 		eap_peap_req_success(sm, data);
+		next_vendor = EAP_VENDOR_IETF;
 		next_type = EAP_TYPE_NONE;
 		break;
 	case FAILURE:
@@ -987,7 +1003,7 @@
 		break;
 	}
 
-	eap_peap_phase2_init(sm, data, next_type);
+	eap_peap_phase2_init(sm, data, next_vendor, next_type);
 }
 
 
@@ -1131,7 +1147,8 @@
 		break;
 	case PHASE2_START:
 		eap_peap_state(data, PHASE2_ID);
-		eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+		eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+				     EAP_TYPE_IDENTITY);
 		break;
 	case PHASE1_ID2:
 	case PHASE2_ID:
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 943af0d..66bd5d2 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "crypto/sha256.h"
+#include "crypto/ms_funcs.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -24,6 +25,7 @@
 	size_t id_server_len;
 	u8 *password;
 	size_t password_len;
+	int password_hash;
 	u32 token;
 	u16 group_num;
 	EAP_PWD_group *grp;
@@ -112,6 +114,7 @@
 	}
 	data->password_len = sm->user->password_len;
 	os_memcpy(data->password, sm->user->password, data->password_len);
+	data->password_hash = sm->user->password_hash;
 
 	data->bnctx = BN_CTX_new();
 	if (data->bnctx == NULL) {
@@ -181,7 +184,8 @@
 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
 	wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
-	wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
+	wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
+		      EAP_PWD_PREP_NONE);
 	wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
 }
 
@@ -579,6 +583,10 @@
 				    const u8 *payload, size_t payload_len)
 {
 	struct eap_pwd_id *id;
+	const u8 *password;
+	size_t password_len;
+	u8 pwhashhash[16];
+	int res;
 
 	if (payload_len < sizeof(struct eap_pwd_id)) {
 		wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
@@ -610,11 +618,25 @@
 			   "group");
 		return;
 	}
-	if (compute_password_element(data->grp, data->group_num,
-				     data->password, data->password_len,
-				     data->id_server, data->id_server_len,
-				     data->id_peer, data->id_peer_len,
-				     (u8 *) &data->token)) {
+
+	if (data->password_hash) {
+		res = hash_nt_password_hash(data->password, pwhashhash);
+		if (res)
+			return;
+		password = pwhashhash;
+		password_len = sizeof(pwhashhash);
+	} else {
+		password = data->password;
+		password_len = data->password_len;
+	}
+
+	res = compute_password_element(data->grp, data->group_num,
+				       password, password_len,
+				       data->id_server, data->id_server_len,
+				       data->id_peer, data->id_peer_len,
+				       (u8 *) &data->token);
+	os_memset(pwhashhash, 0, sizeof(pwhashhash));
+	if (res) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
 			   "PWE");
 		return;
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 56916c4..23498c9 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -100,43 +100,19 @@
 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 			       char *label, size_t len)
 {
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
+	u8 *out;
 
 	out = os_malloc(len);
 	if (out == NULL)
 		return NULL;
 
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-	    0)
-		return out;
+	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
+			       out, len)) {
+		os_free(out);
+		return NULL;
+	}
 
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
-			     label, rnd, keys.client_random_len +
-			     keys.server_random_len, out, len))
-		goto fail;
-
-	os_free(rnd);
 	return out;
-
-fail:
-	os_free(out);
-	os_free(rnd);
-	return NULL;
 }
 
 
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 12a31b0..31c67e8 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -618,6 +618,12 @@
 		return;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	eap_server_mschap_rx_callback(sm, "TTLS-MSCHAP",
+				      sm->identity, sm->identity_len,
+				      challenge, response + 2 + 24);
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN)
 	    != 0 ||
 	    response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
@@ -740,6 +746,18 @@
 	}
 
 	rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
+#ifdef CONFIG_TESTING_OPTIONS
+	{
+		u8 challenge2[8];
+
+		if (challenge_hash(peer_challenge, auth_challenge,
+				   username, username_len, challenge2) == 0) {
+			eap_server_mschap_rx_callback(sm, "TTLS-MSCHAPV2",
+						      username, username_len,
+						      challenge2, rx_resp);
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (os_memcmp_const(nt_response, rx_resp, 24) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
 			   "NT-Response");
diff --git a/src/eapol_auth/Makefile b/src/eapol_auth/Makefile
index adfd3df..7b927a1 100644
--- a/src/eapol_auth/Makefile
+++ b/src/eapol_auth/Makefile
@@ -1,8 +1,16 @@
-all:
-	@echo Nothing to be made.
+all: libeapol_auth.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_auth.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+LIB_OBJS = eapol_auth_sm.o eapol_auth_dump.o
+
+libeapol_auth.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eapol_supp/Makefile b/src/eapol_supp/Makefile
index adfd3df..80db9d4 100644
--- a/src/eapol_supp/Makefile
+++ b/src/eapol_supp/Makefile
@@ -1,8 +1,18 @@
-all:
-	@echo Nothing to be made.
+all: libeapol_supp.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_supp.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS = eapol_supp_sm.o
+
+libeapol_supp.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 941a269..9cc234a 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1634,21 +1634,15 @@
 /**
  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @attempt: Whether PMKSA caching is tried
  *
- * Notify EAPOL state machines whether PMKSA caching is used.
+ * Notify EAPOL state machines if PMKSA caching is used.
  */
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
 {
 	if (sm == NULL)
 		return;
-	if (attempt) {
-		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
-		sm->cached_pmk = TRUE;
-	} else {
-		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
-		sm->cached_pmk = FALSE;
-	}
+	wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
+	sm->cached_pmk = TRUE;
 }
 
 
@@ -1962,13 +1956,14 @@
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 
 static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
-				 const char *cert_hash,
+				 const char *altsubject[],
+				 int num_altsubject, const char *cert_hash,
 				 const struct wpabuf *cert)
 {
 	struct eapol_sm *sm = ctx;
 	if (sm->ctx->cert_cb)
-		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
-				 cert_hash, cert);
+		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
+				 num_altsubject, cert_hash, cert);
 }
 
 
@@ -1982,6 +1977,17 @@
 }
 
 
+#ifdef CONFIG_EAP_PROXY
+static void eapol_sm_eap_proxy_cb(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->eap_proxy_cb)
+		sm->ctx->eap_proxy_cb(sm->ctx->ctx);
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
 static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
 {
 	struct eapol_sm *sm = ctx;
@@ -2005,6 +2011,9 @@
 	eapol_sm_eap_param_needed,
 	eapol_sm_notify_cert,
 	eapol_sm_notify_status,
+#ifdef CONFIG_EAP_PROXY
+	eapol_sm_eap_proxy_cb,
+#endif /* CONFIG_EAP_PROXY */
 	eapol_sm_set_anon_id
 };
 
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index e089e88..1309ff7 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -248,10 +248,13 @@
 	 * @ctx: Callback context (ctx)
 	 * @depth: Depth in certificate chain (0 = server)
 	 * @subject: Subject of the peer certificate
+	 * @altsubject: Select fields from AltSubject of the peer certificate
+	 * @num_altsubject: Number of altsubject values
 	 * @cert_hash: SHA-256 hash of the certificate
 	 * @cert: Peer certificate
 	 */
 	void (*cert_cb)(void *ctx, int depth, const char *subject,
+			const char *altsubject[], int num_altsubject,
 			const char *cert_hash, const struct wpabuf *cert);
 
 	/**
@@ -268,6 +271,14 @@
 	void (*status_cb)(void *ctx, const char *status,
 			  const char *parameter);
 
+#ifdef CONFIG_EAP_PROXY
+	/**
+	 * eap_proxy_cb - Callback signifying any updates from eap_proxy
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 */
+	void (*eap_proxy_cb)(void *ctx);
+#endif /* CONFIG_EAP_PROXY */
+
 	/**
 	 * set_anon_id - Set or add anonymous identity
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
@@ -304,7 +315,7 @@
 const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len);
 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
 void eapol_sm_notify_cached(struct eapol_sm *sm);
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt);
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm);
 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
@@ -377,13 +388,20 @@
 {
 	return -1;
 }
+static inline const u8 *
+eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
+{
+	return NULL;
+}
 static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
 {
 }
 static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
 {
 }
-#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0)
+static inline void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
+{
+}
 #define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0)
 static inline void eapol_sm_notify_portControl(struct eapol_sm *sm,
 					       PortControl portControl)
diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile
index adfd3df..47925b7 100644
--- a/src/l2_packet/Makefile
+++ b/src/l2_packet/Makefile
@@ -1,8 +1,16 @@
-all:
-	@echo Nothing to be made.
+all: libl2_packet.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libl2_packet.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+LIB_OBJS = l2_packet_linux.o
+
+libl2_packet.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index 7537f93..2a45245 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -68,6 +68,19 @@
 	void *rx_callback_ctx, int l2_hdr);
 
 /**
+ * l2_packet_init_bridge - Like l2_packet_init() but with bridge workaround
+ *
+ * This version of l2_packet_init() can be used to enable a workaround for Linux
+ * packet socket in case of a station interface in a bridge.
+ */
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr);
+
+/**
  * l2_packet_deinit - Deinitialize l2_packet interface
  * @l2: Pointer to internal l2_packet data from l2_packet_init()
  */
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
index d87c32b..aa83648 100644
--- a/src/l2_packet/l2_packet_freebsd.c
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -256,6 +256,18 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			      rx_callback_ctx, l2_hdr);
+}
+
+
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 != NULL) {
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 89ff7db..41de2f8 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Layer2 packet handling with Linux packet sockets
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,8 @@
 
 #include "common.h"
 #include "eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/crypto.h"
 #include "l2_packet.h"
 
 
@@ -27,6 +29,12 @@
 	void *rx_callback_ctx;
 	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
 		     * buffers */
+
+	/* For working around Linux packet socket behavior and regression. */
+	int fd_br_rx;
+	int last_from_br;
+	u8 last_hash[SHA1_MAC_LEN];
+	unsigned int num_rx, num_rx_br;
 };
 
 /* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
@@ -119,6 +127,7 @@
 	struct sockaddr_ll ll;
 	socklen_t fromlen;
 
+	l2->num_rx++;
 	os_memset(&ll, 0, sizeof(ll));
 	fromlen = sizeof(ll);
 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
@@ -129,6 +138,80 @@
 		return;
 	}
 
+	wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
+		   __func__, MAC2STR(ll.sll_addr), (int) res);
+
+	if (l2->fd_br_rx >= 0) {
+		u8 hash[SHA1_MAC_LEN];
+		const u8 *addr[1];
+		size_t len[1];
+
+		/*
+		 * Close the workaround socket if the kernel version seems to be
+		 * able to deliver packets through the packet socket before
+		 * authorization has been completed (in dormant state).
+		 */
+		if (l2->num_rx_br <= 1) {
+			wpa_printf(MSG_DEBUG,
+				   "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket",
+				   l2->ifname);
+			eloop_unregister_read_sock(l2->fd_br_rx);
+			close(l2->fd_br_rx);
+			l2->fd_br_rx = -1;
+		}
+
+		addr[0] = buf;
+		len[0] = res;
+		sha1_vector(1, addr, len, hash);
+		if (l2->last_from_br &&
+		    os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) {
+			wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX",
+				   __func__);
+			return;
+		}
+		os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
+	}
+
+	l2->last_from_br = 0;
+	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
+}
+
+
+static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	u8 buf[2300];
+	int res;
+	struct sockaddr_ll ll;
+	socklen_t fromlen;
+	u8 hash[SHA1_MAC_LEN];
+	const u8 *addr[1];
+	size_t len[1];
+
+	l2->num_rx_br++;
+	os_memset(&ll, 0, sizeof(ll));
+	fromlen = sizeof(ll);
+	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
+		       &fromlen);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "l2_packet_receive_br - recvfrom: %s",
+			   strerror(errno));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
+		   __func__, MAC2STR(ll.sll_addr), (int) res);
+
+	addr[0] = buf;
+	len[0] = res;
+	sha1_vector(1, addr, len, hash);
+	if (!l2->last_from_br &&
+	    os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) {
+		wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__);
+		return;
+	}
+	l2->last_from_br = 1;
+	os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
 	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
 }
 
@@ -150,6 +233,7 @@
 	l2->rx_callback = rx_callback;
 	l2->rx_callback_ctx = rx_callback_ctx;
 	l2->l2_hdr = l2_hdr;
+	l2->fd_br_rx = -1;
 
 	l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
 			htons(protocol));
@@ -197,6 +281,87 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+	struct sock_filter ethertype_sock_filter_insns[] = {
+		/* Load ethertype */
+		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 2 * ETH_ALEN),
+		/* Jump over next statement if ethertype does not match */
+		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, protocol, 0, 1),
+		/* Ethertype match - return all */
+		BPF_STMT(BPF_RET | BPF_K, ~0),
+		/* No match - drop */
+		BPF_STMT(BPF_RET | BPF_K, 0)
+	};
+	const struct sock_fprog ethertype_sock_filter = {
+		.len = ARRAY_SIZE(ethertype_sock_filter_insns),
+		.filter = ethertype_sock_filter_insns,
+	};
+	struct sockaddr_ll ll;
+
+	l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			    rx_callback_ctx, l2_hdr);
+	if (!l2)
+		return NULL;
+
+	/*
+	 * The Linux packet socket behavior has changed over the years and there
+	 * is an inconvenient regression in it that breaks RX for a specific
+	 * protocol from interfaces in a bridge when that interface is not in
+	 * fully operation state (i.e., when in station mode and not completed
+	 * authorization). To work around this, register ETH_P_ALL version of
+	 * the packet socket bound to the real netdev and use socket filter to
+	 * match the ethertype value. This version is less efficient, but
+	 * required for functionality with many kernel version. If the main
+	 * packet socket is found to be working, this less efficient version
+	 * gets closed automatically.
+	 */
+
+	l2->fd_br_rx = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
+			      htons(ETH_P_ALL));
+	if (l2->fd_br_rx < 0) {
+		wpa_printf(MSG_DEBUG, "%s: socket(PF_PACKET-fd_br_rx): %s",
+			   __func__, strerror(errno));
+		/* try to continue without the workaround RX socket */
+		return l2;
+	}
+
+	os_memset(&ll, 0, sizeof(ll));
+	ll.sll_family = PF_PACKET;
+	ll.sll_ifindex = if_nametoindex(ifname);
+	ll.sll_protocol = htons(ETH_P_ALL);
+	if (bind(l2->fd_br_rx, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: bind[PF_PACKET-fd_br_rx]: %s",
+			   __func__, strerror(errno));
+		/* try to continue without the workaround RX socket */
+		close(l2->fd_br_rx);
+		l2->fd_br_rx = -1;
+		return l2;
+	}
+
+	if (setsockopt(l2->fd_br_rx, SOL_SOCKET, SO_ATTACH_FILTER,
+		       &ethertype_sock_filter, sizeof(struct sock_fprog))) {
+		wpa_printf(MSG_DEBUG,
+			   "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
+			   strerror(errno));
+		/* try to continue without the workaround RX socket */
+		close(l2->fd_br_rx);
+		l2->fd_br_rx = -1;
+		return l2;
+	}
+
+	eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL);
+
+	return l2;
+}
+
+
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 == NULL)
@@ -206,7 +371,12 @@
 		eloop_unregister_read_sock(l2->fd);
 		close(l2->fd);
 	}
-		
+
+	if (l2->fd_br_rx >= 0) {
+		eloop_unregister_read_sock(l2->fd_br_rx);
+		close(l2->fd_br_rx);
+	}
+
 	os_free(l2);
 }
 
diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c
index 39a62a0..7167781 100644
--- a/src/l2_packet/l2_packet_ndis.c
+++ b/src/l2_packet/l2_packet_ndis.c
@@ -450,6 +450,18 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			      rx_callback_ctx, l2_hdr);
+}
+
+
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 == NULL)
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
index 0501925..307fc6d 100644
--- a/src/l2_packet/l2_packet_none.c
+++ b/src/l2_packet/l2_packet_none.c
@@ -91,6 +91,18 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			      rx_callback_ctx, l2_hdr);
+}
+
+
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 == NULL)
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index 76dcccc..e26ca20 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -231,6 +231,18 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			      rx_callback_ctx, l2_hdr);
+}
+
+
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 == NULL)
diff --git a/src/l2_packet/l2_packet_winpcap.c b/src/l2_packet/l2_packet_winpcap.c
index b6e5088..74085a3 100644
--- a/src/l2_packet/l2_packet_winpcap.c
+++ b/src/l2_packet/l2_packet_winpcap.c
@@ -248,6 +248,18 @@
 }
 
 
+struct l2_packet_data * l2_packet_init_bridge(
+	const char *br_ifname, const char *ifname, const u8 *own_addr,
+	unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+			      rx_callback_ctx, l2_hdr);
+}
+
+
 static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct l2_packet_data *l2 = eloop_ctx;
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
index adfd3df..5587fcf 100644
--- a/src/p2p/Makefile
+++ b/src/p2p/Makefile
@@ -1,8 +1,29 @@
-all:
-	@echo Nothing to be made.
+all: libp2p.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libp2p.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WPS_NFC
+
+LIB_OBJS= \
+	p2p_build.o \
+	p2p.o \
+	p2p_dev_disc.o \
+	p2p_go_neg.o \
+	p2p_group.o \
+	p2p_invitation.o \
+	p2p_parse.o \
+	p2p_pd.o \
+	p2p_sd.o \
+	p2p_utils.o
+
+libp2p.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 77bd7fc..a45fe73 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -13,6 +13,8 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
 #include "p2p.h"
@@ -151,6 +153,19 @@
 }
 
 
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p)
+{
+	return p2p ? p2p->p2ps_adv_list : NULL;
+}
+
+
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr)
+{
+	if (p2p && intended_addr)
+		os_memcpy(p2p->intended_addr, intended_addr, ETH_ALEN);
+}
+
+
 u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
 {
 	struct p2p_device *dev = NULL;
@@ -763,6 +778,7 @@
 	if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
 		os_memcpy(dev->interface_addr, addr, ETH_ALEN);
 	if (msg.ssid &&
+	    msg.ssid[1] <= sizeof(dev->oper_ssid) &&
 	    (msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
 	     os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
 	     != 0)) {
@@ -770,6 +786,12 @@
 		dev->oper_ssid_len = msg.ssid[1];
 	}
 
+	if (msg.adv_service_instance && msg.adv_service_instance_len) {
+		wpabuf_free(dev->info.p2ps_instance);
+		dev->info.p2ps_instance = wpabuf_alloc_copy(
+			msg.adv_service_instance, msg.adv_service_instance_len);
+	}
+
 	if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
 	    *msg.ds_params >= 1 && *msg.ds_params <= 14) {
 		int ds_freq;
@@ -829,7 +851,9 @@
 
 	p2p_update_peer_vendor_elems(dev, ies, ies_len);
 
-	if (dev->flags & P2P_DEV_REPORTED && !wfd_changed)
+	if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+	    (!msg.adv_service_instance ||
+	     (dev->flags & P2P_DEV_P2PS_REPORTED)))
 		return 0;
 
 	p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
@@ -865,6 +889,9 @@
 			    !(dev->flags & P2P_DEV_REPORTED_ONCE));
 	dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
 
+	if (msg.adv_service_instance)
+		dev->flags |= P2P_DEV_P2PS_REPORTED;
+
 	return 0;
 }
 
@@ -899,6 +926,7 @@
 	wpabuf_free(dev->info.wfd_subelems);
 	wpabuf_free(dev->info.vendor_elems);
 	wpabuf_free(dev->go_neg_conf);
+	wpabuf_free(dev->info.p2ps_instance);
 
 	os_free(dev);
 }
@@ -1083,10 +1111,44 @@
 }
 
 
+static int p2ps_gen_hash(struct p2p_data *p2p, const char *str, u8 *hash)
+{
+	u8 buf[SHA256_MAC_LEN];
+	char str_buf[256];
+	const u8 *adv_array;
+	size_t i, adv_len;
+
+	if (!str || !hash)
+		return 0;
+
+	if (!str[0]) {
+		os_memcpy(hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+		return 1;
+	}
+
+	adv_array = (u8 *) str_buf;
+	adv_len = os_strlen(str);
+
+	for (i = 0; str[i] && i < adv_len; i++) {
+		if (str[i] >= 'A' && str[i] <= 'Z')
+			str_buf[i] = str[i] - 'A' + 'a';
+		else
+			str_buf[i] = str[i];
+	}
+
+	if (sha256_vector(1, &adv_array, &adv_len, buf))
+		return 0;
+
+	os_memcpy(hash, buf, P2PS_HASH_LEN);
+	return 1;
+}
+
+
 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, unsigned int search_delay)
+	     const u8 *dev_id, unsigned int search_delay,
+	     u8 seek_count, const char **seek, int freq)
 {
 	int res;
 
@@ -1113,6 +1175,47 @@
 	} else
 		p2p->find_dev_id = NULL;
 
+	if (seek_count == 0 || !seek) {
+		/* Not an ASP search */
+		p2p->p2ps_seek = 0;
+	} else if (seek_count == 1 && seek && (!seek[0] || !seek[0][0])) {
+		/*
+		 * An empty seek string means no hash values, but still an ASP
+		 * search.
+		 */
+		p2p->p2ps_seek_count = 0;
+		p2p->p2ps_seek = 1;
+	} else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
+		u8 buf[P2PS_HASH_LEN];
+		int i;
+
+		p2p->p2ps_seek_count = seek_count;
+		for (i = 0; i < seek_count; i++) {
+			if (!p2ps_gen_hash(p2p, seek[i], buf))
+				continue;
+
+			/* If asking for wildcard, don't do others */
+			if (os_memcmp(buf, p2p->wild_card_hash,
+				      P2PS_HASH_LEN) == 0) {
+				p2p->p2ps_seek_count = 0;
+				break;
+			}
+
+			os_memcpy(&p2p->query_hash[i * P2PS_HASH_LEN], buf,
+				  P2PS_HASH_LEN);
+		}
+		p2p->p2ps_seek = 1;
+	} else {
+		p2p->p2ps_seek_count = 0;
+		p2p->p2ps_seek = 1;
+	}
+
+	/* Special case to perform wildcard search */
+	if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
+		p2p->p2ps_seek_count = 1;
+		os_memcpy(&p2p->query_hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+	}
+
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
 	p2p_clear_timeout(p2p);
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -1128,6 +1231,19 @@
 				       p2p, NULL);
 	switch (type) {
 	case P2P_FIND_START_WITH_FULL:
+		if (freq > 0) {
+			/*
+			 * Start with the specified channel and then move to
+			 * social channels only scans.
+			 */
+			res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
+						 P2P_SCAN_SPECIFIC, freq,
+						 p2p->num_req_dev_types,
+						 p2p->req_dev_types, dev_id,
+						 DEV_PW_DEFAULT);
+			break;
+		}
+		/* fall through */
 	case P2P_FIND_PROGRESSIVE:
 		res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
 					 p2p->num_req_dev_types,
@@ -1163,8 +1279,11 @@
 	p2p_dbg(p2p, "Stopping find");
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	p2p_clear_timeout(p2p);
-	if (p2p->state == P2P_SEARCH)
+	if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
 		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
+
+	p2p->p2ps_seek_count = 0;
+
 	p2p_set_state(p2p, P2P_IDLE);
 	p2p_free_req_dev_types(p2p);
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
@@ -1174,6 +1293,7 @@
 	p2p->sd_peer = NULL;
 	p2p->invite_peer = NULL;
 	p2p_stop_listen_for_freq(p2p, freq);
+	p2p->send_action_in_progress = 0;
 }
 
 
@@ -1637,7 +1757,14 @@
 
 int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
 {
-	p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
+	if (p2p->ssid_set) {
+		os_memcpy(params->ssid, p2p->ssid, p2p->ssid_len);
+		params->ssid_len = p2p->ssid_len;
+	} else {
+		p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
+	}
+	p2p->ssid_set = 0;
+
 	p2p_random(params->passphrase, p2p->cfg->passphrase_len);
 	return 0;
 }
@@ -2036,6 +2163,9 @@
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
 
+	if (p2p->query_count)
+		extra += MAX_SVC_ADV_IE_LEN;
+
 	buf = wpabuf_alloc(1000 + extra);
 	if (buf == NULL)
 		return NULL;
@@ -2070,10 +2200,38 @@
 	p2p_buf_add_device_info(buf, p2p, NULL);
 	p2p_buf_update_ie_hdr(buf, len);
 
+	if (p2p->query_count) {
+		p2p_buf_add_service_instance(buf, p2p, p2p->query_count,
+					     p2p->query_hash,
+					     p2p->p2ps_adv_list);
+	}
+
 	return buf;
 }
 
 
+static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
+{
+	struct p2ps_advertisement *adv_data;
+
+	p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
+
+	/* Wildcard always matches if we have actual services */
+	if (os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
+		return p2p->p2ps_adv_list != NULL;
+
+	adv_data = p2p->p2ps_adv_list;
+	while (adv_data) {
+		p2p_dbg(p2p, "ASP hash: %x =? %x", hash[0], adv_data->hash[0]);
+		if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
+			return 1;
+		adv_data = adv_data->next;
+	}
+
+	return 0;
+}
+
+
 static enum p2p_probe_req_status
 p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
 		const u8 *bssid, const u8 *ie, size_t ie_len)
@@ -2084,13 +2242,6 @@
 	struct p2p_message msg;
 	struct wpabuf *ies;
 
-	if (!p2p->in_listen || !p2p->drv_in_listen) {
-		/* not in Listen state - ignore Probe Request */
-		p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
-			p2p->in_listen, p2p->drv_in_listen);
-		return P2P_PREQ_NOT_LISTEN;
-	}
-
 	if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
 	    ParseFailed) {
 		/* Ignore invalid Probe Request frames */
@@ -2141,6 +2292,64 @@
 		return P2P_PREQ_NOT_P2P;
 	}
 
+	p2p->p2ps_svc_found = 0;
+
+	if (msg.service_hash && msg.service_hash_count) {
+		const u8 *hash = msg.service_hash;
+		u8 *dest = p2p->query_hash;
+		u8 i;
+
+		p2p->query_count = 0;
+		for (i = 0; i < msg.service_hash_count; i++) {
+			if (p2p_service_find_asp(p2p, hash)) {
+				p2p->p2ps_svc_found = 1;
+
+				if (!os_memcmp(hash, p2p->wild_card_hash,
+					       P2PS_HASH_LEN)) {
+					/* We found match(es) but wildcard
+					 * will return all */
+					p2p->query_count = 1;
+					os_memcpy(p2p->query_hash, hash,
+						  P2PS_HASH_LEN);
+					break;
+				}
+
+				/* Save each matching hash */
+				if (p2p->query_count < P2P_MAX_QUERY_HASH) {
+					os_memcpy(dest, hash, P2PS_HASH_LEN);
+					dest += P2PS_HASH_LEN;
+					p2p->query_count++;
+				} else {
+					/* We found match(es) but too many to
+					 * return all */
+					p2p->query_count = 0;
+					break;
+				}
+			}
+			hash += P2PS_HASH_LEN;
+		}
+
+		p2p_dbg(p2p, "ASP adv found: %d", p2p->p2ps_svc_found);
+
+		/* Probed hash unknown */
+		if (!p2p->p2ps_svc_found) {
+			p2p_parse_free(&msg);
+			return P2P_PREQ_NOT_PROCESSED;
+		}
+	} else {
+		/* This is not a P2PS Probe Request */
+		p2p->query_count = 0;
+		p2p_dbg(p2p, "No P2PS Hash in Probe Request");
+
+		if (!p2p->in_listen || !p2p->drv_in_listen) {
+			/* not in Listen state - ignore Probe Request */
+			p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
+				p2p->in_listen, p2p->drv_in_listen);
+			p2p_parse_free(&msg);
+			return P2P_PREQ_NOT_LISTEN;
+		}
+	}
+
 	if (msg.device_id &&
 	    os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
 		/* Device ID did not match */
@@ -2238,6 +2447,7 @@
 	p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
 	res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+	p2p->query_count = 0;
 
 	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
 	    p2p->go_neg_peer &&
@@ -2395,6 +2605,151 @@
 }
 
 
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id)
+{
+	struct p2ps_advertisement *adv_data;
+
+	if (!p2p)
+		return NULL;
+
+	adv_data = p2p->p2ps_adv_list;
+	while (adv_data) {
+		if (adv_data->id == adv_id)
+			return adv_data;
+		adv_data = adv_data->next;
+	}
+
+	return NULL;
+}
+
+
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id)
+{
+	struct p2ps_advertisement *adv_data;
+	struct p2ps_advertisement **prior;
+
+	if (!p2p)
+		return -1;
+
+	adv_data = p2p->p2ps_adv_list;
+	prior = &p2p->p2ps_adv_list;
+	while (adv_data) {
+		if (adv_data->id == adv_id) {
+			p2p_dbg(p2p, "Delete ASP adv_id=0x%x", adv_id);
+			*prior = adv_data->next;
+			os_free(adv_data);
+			return 0;
+		}
+		prior = &adv_data->next;
+		adv_data = adv_data->next;
+	}
+
+	return -1;
+}
+
+
+int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
+			const char *adv_str, u8 svc_state, u16 config_methods,
+			const char *svc_info)
+{
+	struct p2ps_advertisement *adv_data, *tmp, **prev;
+	u8 buf[P2PS_HASH_LEN];
+	size_t adv_data_len, adv_len, info_len = 0;
+
+	if (!p2p || !adv_str || !adv_str[0])
+		return -1;
+
+	if (!(config_methods & p2p->cfg->config_methods)) {
+		p2p_dbg(p2p, "Config methods not supported svc: 0x%x dev: 0x%x",
+			config_methods, p2p->cfg->config_methods);
+		return -1;
+	}
+
+	if (!p2ps_gen_hash(p2p, adv_str, buf))
+		return -1;
+
+	if (svc_info)
+		info_len = os_strlen(svc_info);
+	adv_len = os_strlen(adv_str);
+	adv_data_len = sizeof(struct p2ps_advertisement) + adv_len + 1 +
+		info_len + 1;
+
+	adv_data = os_zalloc(adv_data_len);
+	if (!adv_data)
+		return -1;
+
+	os_memcpy(adv_data->hash, buf, P2PS_HASH_LEN);
+	adv_data->id = adv_id;
+	adv_data->state = svc_state;
+	adv_data->config_methods = config_methods & p2p->cfg->config_methods;
+	adv_data->auto_accept = (u8) auto_accept;
+	os_memcpy(adv_data->svc_name, adv_str, adv_len);
+
+	if (svc_info && info_len) {
+		adv_data->svc_info = &adv_data->svc_name[adv_len + 1];
+		os_memcpy(adv_data->svc_info, svc_info, info_len);
+	}
+
+	/*
+	 * Group Advertisements by service string. They do not need to be
+	 * sorted, but groups allow easier Probe Response instance grouping
+	 */
+	tmp = p2p->p2ps_adv_list;
+	prev = &p2p->p2ps_adv_list;
+	while (tmp) {
+		if (tmp->id == adv_data->id) {
+			if (os_strcmp(tmp->svc_name, adv_data->svc_name) != 0) {
+				os_free(adv_data);
+				return -1;
+			}
+			adv_data->next = tmp->next;
+			*prev = adv_data;
+			os_free(tmp);
+			goto inserted;
+		} else {
+			if (os_strcmp(tmp->svc_name, adv_data->svc_name) == 0) {
+				adv_data->next = tmp->next;
+				tmp->next = adv_data;
+				goto inserted;
+			}
+		}
+		prev = &tmp->next;
+		tmp = tmp->next;
+	}
+
+	/* No svc_name match found */
+	adv_data->next = p2p->p2ps_adv_list;
+	p2p->p2ps_adv_list = adv_data;
+
+inserted:
+	p2p_dbg(p2p,
+		"Added ASP advertisement adv_id=0x%x config_methods=0x%x svc_state=0x%x adv_str='%s'",
+		adv_id, adv_data->config_methods, svc_state, adv_str);
+
+	return 0;
+}
+
+
+void p2p_service_flush_asp(struct p2p_data *p2p)
+{
+	struct p2ps_advertisement *adv, *prev;
+
+	if (!p2p)
+		return;
+
+	adv = p2p->p2ps_adv_list;
+	while (adv) {
+		prev = adv;
+		adv = adv->next;
+		os_free(prev);
+	}
+
+	p2p->p2ps_adv_list = NULL;
+	p2p_dbg(p2p, "All ASP advertisements flushed");
+}
+
+
 int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
 {
 	struct p2p_message msg;
@@ -2508,6 +2863,8 @@
 			p2p->cfg->num_pref_chan = 0;
 	}
 
+	p2ps_gen_hash(p2p, P2PS_WILD_HASH_STR, p2p->wild_card_hash);
+
 	p2p->min_disc_int = 1;
 	p2p->max_disc_int = 3;
 	p2p->max_disc_tu = -1;
@@ -2569,10 +2926,13 @@
 	os_free(p2p->cfg->serial_number);
 	os_free(p2p->cfg->pref_chan);
 	os_free(p2p->groups);
+	os_free(p2p->p2ps_prov);
 	wpabuf_free(p2p->sd_resp);
 	os_free(p2p->after_scan_tx);
 	p2p_remove_wps_vendor_extensions(p2p);
 	os_free(p2p->no_go_freq.range);
+	p2p_service_flush_asp(p2p);
+
 	os_free(p2p);
 }
 
@@ -2837,17 +3197,19 @@
 		if (p2p->sd_peer)
 			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p->sd_peer = NULL;
-		p2p_continue_find(p2p);
+		if (p2p->state != P2P_IDLE)
+			p2p_continue_find(p2p);
 		return;
 	}
 
 	if (p2p->sd_peer == NULL) {
 		p2p_dbg(p2p, "No SD peer entry known");
-		p2p_continue_find(p2p);
+		if (p2p->state != P2P_IDLE)
+			p2p_continue_find(p2p);
 		return;
 	}
 
-	if (p2p->sd_query->for_all_peers) {
+	if (p2p->sd_query && p2p->sd_query->for_all_peers) {
 		/* Update the pending broadcast SD query count for this device
 		 */
 		p2p->sd_peer->sd_pending_bcast_queries--;
@@ -2874,9 +3236,6 @@
 {
 	struct p2p_device *dev;
 
-	if (p2p->state != P2P_IDLE)
-		return;
-
 	/*
 	 * Retry the prov disc req attempt only for the peer that the user had
 	 * requested.
@@ -2950,6 +3309,51 @@
 }
 
 
+static int p2p_check_after_scan_tx_continuation(struct p2p_data *p2p)
+{
+	if (p2p->after_scan_tx_in_progress) {
+		p2p->after_scan_tx_in_progress = 0;
+		if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
+		    p2p_run_after_scan(p2p))
+			return 1;
+		if (p2p->state == P2P_SEARCH) {
+			p2p_dbg(p2p, "Continue find after after_scan_tx completion");
+			p2p_continue_find(p2p);
+		}
+	}
+
+	return 0;
+}
+
+
+static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
+{
+	p2p_dbg(p2p, "Provision Discovery Response TX callback: success=%d",
+		success);
+
+	if (p2p->send_action_in_progress) {
+		p2p->send_action_in_progress = 0;
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+	}
+
+	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	if (!success)
+		goto continue_search;
+
+	if (!p2p->cfg->prov_disc_resp_cb ||
+	    p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
+		goto continue_search;
+
+	p2p_dbg(p2p,
+		"Post-Provision Discovery operations started - do not try to continue other P2P operations");
+	return;
+
+continue_search:
+	p2p_check_after_scan_tx_continuation(p2p);
+}
+
+
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
 			 struct os_reltime *rx_time, int level, const u8 *ies,
 			 size_t ies_len)
@@ -2992,6 +3396,7 @@
 
 void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
 {
+	u8 dev_capab;
 	u8 *len;
 
 #ifdef CONFIG_WIFI_DISPLAY
@@ -3004,8 +3409,15 @@
 			       p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
 
 	len = p2p_buf_add_ie_hdr(ies);
-	p2p_buf_add_capability(ies, p2p->dev_capab &
-			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+
+	dev_capab = p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+
+	/* P2PS requires Probe Request frames to include SD bit */
+	if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+		dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
+
+	p2p_buf_add_capability(ies, dev_capab, 0);
+
 	if (dev_id)
 		p2p_buf_add_device_id(ies, dev_id);
 	if (p2p->cfg->reg_class && p2p->cfg->channel)
@@ -3015,6 +3427,10 @@
 	if (p2p->ext_listen_interval)
 		p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
 					      p2p->ext_listen_interval);
+
+	if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+		p2p_buf_add_service_hash(ies, p2p);
+
 	/* TODO: p2p_buf_add_operating_channel() if GO */
 	p2p_buf_update_ie_hdr(ies, len);
 }
@@ -3117,13 +3533,19 @@
 	p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
 	if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
-	} else if (success) {
+		return;
+	}
+
+	if (success) {
 		struct p2p_device *dev;
 		dev = p2p_get_device(p2p, addr);
 		if (dev &&
 		    dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
 			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
 	}
+
+	if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
+		p2p_continue_find(p2p);
 }
 
 
@@ -3200,9 +3622,9 @@
 	int success;
 
 	p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
-		" src=" MACSTR " bssid=" MACSTR " result=%d",
+		" src=" MACSTR " bssid=" MACSTR " result=%d p2p_state=%s)",
 		p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
-		MAC2STR(bssid), result);
+		MAC2STR(bssid), result, p2p_state_txt(p2p->state));
 	success = result == P2P_SEND_ACTION_SUCCESS;
 	state = p2p->pending_action_state;
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
@@ -3212,16 +3634,7 @@
 			p2p->send_action_in_progress = 0;
 			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		}
-		if (p2p->after_scan_tx_in_progress) {
-			p2p->after_scan_tx_in_progress = 0;
-			if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
-			    p2p_run_after_scan(p2p))
-				break;
-			if (p2p->state == P2P_SEARCH) {
-				p2p_dbg(p2p, "Continue find after after_scan_tx completion");
-				p2p_continue_find(p2p);
-			}
-		}
+		p2p_check_after_scan_tx_continuation(p2p);
 		break;
 	case P2P_PENDING_GO_NEG_REQUEST:
 		p2p_go_neg_req_cb(p2p, success);
@@ -3241,6 +3654,9 @@
 	case P2P_PENDING_PD:
 		p2p_prov_disc_cb(p2p, success);
 		break;
+	case P2P_PENDING_PD_RESPONSE:
+		p2p_prov_disc_resp_cb(p2p, success);
+		break;
 	case P2P_PENDING_INVITATION_REQUEST:
 		p2p_invitation_req_cb(p2p, success);
 		break;
@@ -3447,6 +3863,9 @@
 
 static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
 {
+	u32 adv_id = 0;
+	u8 *adv_mac = NULL;
+
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
 	/*
@@ -3475,12 +3894,18 @@
 				for_join = 1;
 		}
 
+		if (p2p->p2ps_prov) {
+			adv_id = p2p->p2ps_prov->adv_id;
+			adv_mac = p2p->p2ps_prov->adv_mac;
+		}
+
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
 						 p2p->pending_pd_devaddr,
 						 for_join ?
 						 P2P_PROV_DISC_TIMEOUT_JOIN :
-						 P2P_PROV_DISC_TIMEOUT);
+						 P2P_PROV_DISC_TIMEOUT,
+						 adv_id, adv_mac, NULL);
 		p2p_reset_pending_pd(p2p);
 	}
 }
@@ -3629,6 +4054,8 @@
 		return "PBC";
 	case WPS_NFC:
 		return "NFC";
+	case WPS_P2PS:
+		return "P2PS";
 	}
 
 	return "??";
@@ -3705,7 +4132,7 @@
 			  "country=%c%c\n"
 			  "oper_freq=%d\n"
 			  "req_config_methods=0x%x\n"
-			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
 			  "status=%d\n"
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
@@ -3731,6 +4158,8 @@
 			  "[PD_PEER_DISPLAY]" : "",
 			  dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
 			  "[PD_PEER_KEYPAD]" : "",
+			  dev->flags & P2P_DEV_PD_PEER_P2PS ?
+			  "[PD_PEER_P2PS]" : "",
 			  dev->flags & P2P_DEV_USER_REJECTED ?
 			  "[USER_REJECTED]" : "",
 			  dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ?
@@ -4162,15 +4591,18 @@
 	if (p2p_channel_to_freq(reg_class, channel) < 0)
 		return -1;
 
-	p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
-		reg_class, channel);
-
 	/*
 	 * Listen channel was set in configuration or set by control interface;
 	 * cannot override it.
 	 */
-	if (p2p->cfg->channel_forced && forced == 0)
+	if (p2p->cfg->channel_forced && forced == 0) {
+		p2p_dbg(p2p,
+			"Listen channel was previously configured - do not override based on optimization");
 		return -1;
+	}
+
+	p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
+		reg_class, channel);
 
 	if (p2p->state == P2P_IDLE) {
 		p2p->cfg->reg_class = reg_class;
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fa886f7..da2446d 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -9,7 +9,18 @@
 #ifndef P2P_H
 #define P2P_H
 
-#include "wps/wps_defs.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps.h"
+
+/* P2P ASP Setup Capability */
+#define P2PS_SETUP_NONE 0
+#define P2PS_SETUP_NEW BIT(0)
+#define P2PS_SETUP_CLIENT BIT(1)
+#define P2PS_SETUP_GROUP_OWNER BIT(2)
+
+#define P2PS_WILD_HASH_STR "org.wi-fi.wfds"
+#define P2PS_HASH_LEN 6
+#define P2P_MAX_QUERY_HASH 6
 
 /**
  * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
@@ -52,7 +63,8 @@
 };
 
 enum p2p_wps_method {
-	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC
+	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC,
+	WPS_P2PS
 };
 
 /**
@@ -84,7 +96,7 @@
 	/**
 	 * ssid - SSID of the group
 	 */
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 
 	/**
 	 * ssid_len - Length of SSID in octets
@@ -142,11 +154,99 @@
 	unsigned int peer_config_timeout;
 };
 
+struct p2ps_provision {
+	/**
+	 * status - Remote returned provisioning status code
+	 */
+	int status;
+
+	/**
+	 * adv_id - P2PS Advertisement ID
+	 */
+	u32 adv_id;
+
+	/**
+	 * session_id - P2PS Session ID
+	 */
+	u32 session_id;
+
+	/**
+	 * method - WPS Method (to be) used to establish session
+	 */
+	u16 method;
+
+	/**
+	 * conncap - Connection Capabilities negotiated between P2P peers
+	 */
+	u8 conncap;
+
+	/**
+	 * role - Info about the roles to be used for this connection
+	 */
+	u8 role;
+
+	/**
+	 * session_mac - MAC address of the peer that started the session
+	 */
+	u8 session_mac[ETH_ALEN];
+
+	/**
+	 * adv_mac - MAC address of the peer advertised the service
+	 */
+	u8 adv_mac[ETH_ALEN];
+
+	/**
+	 * info - Vendor defined extra Provisioning information
+	 */
+	char info[0];
+};
+
+struct p2ps_advertisement {
+	struct p2ps_advertisement *next;
+
+	/**
+	 * svc_info - Pointer to (internal) Service defined information
+	 */
+	char *svc_info;
+
+	/**
+	 * id - P2PS Advertisement ID
+	 */
+	u32 id;
+
+	/**
+	 * config_methods - WPS Methods which are allowed for this service
+	 */
+	u16 config_methods;
+
+	/**
+	 * state - Current state of the service: 0 - Out Of Service, 1-255 Vendor defined
+	 */
+	u8 state;
+
+	/**
+	 * auto_accept - Automatically Accept provisioning request if possible.
+	 */
+	u8 auto_accept;
+
+	/**
+	 * hash - 6 octet Service Name has to match against incoming Probe Requests
+	 */
+	u8 hash[P2PS_HASH_LEN];
+
+	/**
+	 * svc_name - NULL Terminated UTF-8 Service Name, and svc_info storage
+	 */
+	char svc_name[0];
+};
+
+
 struct p2p_data;
 
 enum p2p_scan_type {
 	P2P_SCAN_SOCIAL,
 	P2P_SCAN_FULL,
+	P2P_SCAN_SPECIFIC,
 	P2P_SCAN_SOCIAL_PLUS_ONE
 };
 
@@ -169,27 +269,27 @@
 	/**
 	 * device_name - Device Name (0..32 octets encoded in UTF-8)
 	 */
-	char device_name[33];
+	char device_name[WPS_DEV_NAME_MAX_LEN + 1];
 
 	/**
 	 * manufacturer - Manufacturer (0..64 octets encoded in UTF-8)
 	 */
-	char manufacturer[65];
+	char manufacturer[WPS_MANUFACTURER_MAX_LEN + 1];
 
 	/**
 	 * model_name - Model Name (0..32 octets encoded in UTF-8)
 	 */
-	char model_name[33];
+	char model_name[WPS_MODEL_NAME_MAX_LEN + 1];
 
 	/**
 	 * model_number - Model Number (0..32 octets encoded in UTF-8)
 	 */
-	char model_number[33];
+	char model_number[WPS_MODEL_NUMBER_MAX_LEN + 1];
 
 	/**
 	 * serial_number - Serial Number (0..32 octets encoded in UTF-8)
 	 */
-	char serial_number[33];
+	char serial_number[WPS_SERIAL_NUMBER_MAX_LEN + 1];
 
 	/**
 	 * level - Signal level
@@ -217,7 +317,7 @@
 	 * This list includes from 0 to 16 Secondary Device Types as indicated
 	 * by wps_sec_dev_type_list_len (8 * number of types).
 	 */
-	u8 wps_sec_dev_type_list[128];
+	u8 wps_sec_dev_type_list[WPS_SEC_DEV_TYPE_MAX_LEN];
 
 	/**
 	 * wps_sec_dev_type_list_len - Length of secondary device type list
@@ -238,6 +338,11 @@
 	 * IE(s) from the frame that was used to discover the peer.
 	 */
 	struct wpabuf *vendor_elems;
+
+	/**
+	 * p2ps_instance - P2PS Application Service Info
+	 */
+	struct wpabuf *p2ps_instance;
 };
 
 enum p2p_prov_disc_status {
@@ -245,6 +350,7 @@
 	P2P_PROV_DISC_TIMEOUT,
 	P2P_PROV_DISC_REJECTED,
 	P2P_PROV_DISC_TIMEOUT_JOIN,
+	P2P_PROV_DISC_INFO_UNAVAILABLE,
 };
 
 struct p2p_channel {
@@ -390,7 +496,7 @@
 	 * This data will be added to the end of the SSID after the
 	 * DIRECT-<random two octets> prefix.
 	 */
-	u8 ssid_postfix[32 - 9];
+	u8 ssid_postfix[SSID_MAX_LEN - 9];
 
 	/**
 	 * ssid_postfix_len - Length of the ssid_postfix data
@@ -441,7 +547,8 @@
 	 * operation to be completed. Type type argument specifies which type
 	 * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
 	 * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
-	 * indicates that all channels are to be scanned.
+	 * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
+	 * request a scan of a single channel specified by freq.
 	 * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
 	 * plus one extra channel specified by freq.
 	 *
@@ -705,6 +812,9 @@
 	 * @ctx: Callback context from cb_ctx
 	 * @peer: Source address of the response
 	 * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+	 * @adv_id: If non-zero, then the adv_id of the PD Request
+	 * @adv_mac: P2P Device Address of the advertizer
+	 * @deferred_session_resp: Deferred session response sent by advertizer
 	 *
 	 * This callback is used to indicate either a failure or no response
 	 * to an earlier provision discovery request.
@@ -713,7 +823,9 @@
 	 * is not used or failures do not need to be indicated.
 	 */
 	void (*prov_disc_fail)(void *ctx, const u8 *peer,
-			       enum p2p_prov_disc_status status);
+			       enum p2p_prov_disc_status status,
+			       u32 adv_id, const u8 *adv_mac,
+			       const char *deferred_session_resp);
 
 	/**
 	 * invitation_process - Optional callback for processing Invitations
@@ -835,6 +947,83 @@
 	 * or 0 if not.
 	 */
 	int (*is_p2p_in_progress)(void *ctx);
+
+	/**
+	 * Determine if we have a persistent group we share with remote peer
+	 * @ctx: Callback context from cb_ctx
+	 * @addr: Peer device address to search for
+	 * @ssid: Persistent group SSID or %NULL if any
+	 * @ssid_len: Length of @ssid
+	 * @go_dev_addr: Buffer for returning intended GO P2P Device Address
+	 * @ret_ssid: Buffer for returning group SSID
+	 * @ret_ssid_len: Buffer for returning length of @ssid
+	 * Returns: 1 if a matching persistent group was found, 0 otherwise
+	 */
+	int (*get_persistent_group)(void *ctx, const u8 *addr, const u8 *ssid,
+				    size_t ssid_len, u8 *go_dev_addr,
+				    u8 *ret_ssid, size_t *ret_ssid_len);
+
+	/**
+	 * Get information about a possible local GO role
+	 * @ctx: Callback context from cb_ctx
+	 * @intended_addr: Buffer for returning intended GO interface address
+	 * @ssid: Buffer for returning group SSID
+	 * @ssid_len: Buffer for returning length of @ssid
+	 * @group_iface: Buffer for returning whether a separate group interface
+	 *	would be used
+	 * Returns: 1 if GO info found, 0 otherwise
+	 *
+	 * This is used to compose New Group settings (SSID, and intended
+	 * address) during P2PS provisioning if results of provisioning *might*
+	 * result in our being an autonomous GO.
+	 */
+	int (*get_go_info)(void *ctx, u8 *intended_addr,
+			   u8 *ssid, size_t *ssid_len, int *group_iface);
+
+	/**
+	 * remove_stale_groups - Remove stale P2PS groups
+	 *
+	 * Because P2PS stages *potential* GOs, and remote devices can remove
+	 * credentials unilaterally, we need to make sure we don't let stale
+	 * unusable groups build up.
+	 */
+	int (*remove_stale_groups)(void *ctx, const u8 *peer, const u8 *go,
+				   const u8 *ssid, size_t ssid_len);
+
+	/**
+	 * p2ps_prov_complete - P2PS provisioning complete
+	 *
+	 * When P2PS provisioning completes (successfully or not) we must
+	 * transmit all of the results to the upper layers.
+	 */
+	void (*p2ps_prov_complete)(void *ctx, u8 status, const u8 *dev,
+				   const u8 *adv_mac, const u8 *ses_mac,
+				   const u8 *grp_mac, u32 adv_id, u32 ses_id,
+				   u8 conncap, int passwd_id,
+				   const u8 *persist_ssid,
+				   size_t persist_ssid_size, int response_done,
+				   int prov_start, const char *session_info);
+
+	/**
+	 * prov_disc_resp_cb - Callback for indicating completion of PD Response
+	 * @ctx: Callback context from cb_ctx
+	 * Returns: 1 if operation was started, 0 otherwise
+	 *
+	 * This callback can be used to perform any pending actions after
+	 * provisioning. It is mainly used for P2PS pending group creation.
+	 */
+	int (*prov_disc_resp_cb)(void *ctx);
+
+	/**
+	 * p2ps_group_capability - Determine group capability
+	 *
+	 * This function can be used to determine group capability based on
+	 * information from P2PS PD exchange and the current state of ongoing
+	 * groups and driver capabilities.
+	 *
+	 * P2PS_SETUP_* bitmap is used as the parameters and return value.
+	 */
+	u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
 };
 
 
@@ -941,12 +1130,19 @@
  *	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
+ * @seek_count: Number of ASP Service Strings in the seek_string array
+ * @seek_string: ASP Service Strings to query for in Probe Requests
+ * @freq: Requested first scan frequency (in MHz) to modify type ==
+ *	P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan.
+ *	If p2p_find is already in progress, this parameter is ignored and full
+ *	scan will be executed.
  * 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, unsigned int search_delay);
+	     const u8 *dev_id, unsigned int search_delay,
+	     u8 seek_count, const char **seek_string, int freq);
 
 /**
  * p2p_notify_scan_trigger_status - Indicate scan trigger status
@@ -1058,6 +1254,7 @@
  * p2p_prov_disc_req - Send Provision Discovery Request
  * @p2p: P2P module context from p2p_init()
  * @peer_addr: MAC address of the peer P2P client
+ * @p2ps_prov: Provisioning info for P2PS
  * @config_methods: WPS Config Methods value (only one bit set)
  * @join: Whether this is used by a client joining an active group
  * @force_freq: Forced TX frequency for the frame (mainly for the join case)
@@ -1073,7 +1270,8 @@
  * indicated with the p2p_config::prov_disc_resp() callback.
  */
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-		      u16 config_methods, int join, int force_freq,
+		      struct p2ps_provision *p2ps_prov, u16 config_methods,
+		      int join, int force_freq,
 		      int user_initiated_pd);
 
 /**
@@ -1410,7 +1608,7 @@
 	/**
 	 * ssid - Group SSID
 	 */
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 
 	/**
 	 * ssid_len - Length of SSID
@@ -1816,6 +2014,13 @@
 unsigned int p2p_get_group_num_members(struct p2p_group *group);
 
 /**
+ * p2p_client_limit_reached - Check if client limit is reached
+ * @group: P2P group context from p2p_group_init()
+ * Returns: 1 if no of clients limit reached
+ */
+int p2p_client_limit_reached(struct p2p_group *group);
+
+/**
  * p2p_iterate_group_members - Iterate group members
  * @group: P2P group context from p2p_group_init()
  * @next: iteration pointer, must be a pointer to a void * that is set to %NULL
@@ -2010,7 +2215,7 @@
 	size_t oob_dev_pw_len;
 	int go_freq;
 	u8 go_dev_addr[ETH_ALEN];
-	u8 go_ssid[32];
+	u8 go_ssid[SSID_MAX_LEN];
 	size_t go_ssid_len;
 };
 
@@ -2030,4 +2235,15 @@
 
 void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem);
 
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr);
+
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id);
+int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
+			const char *adv_str, u8 svc_state,
+			u16 config_methods, const char *svc_info);
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id);
+void p2p_service_flush_asp(struct p2p_data *p2p);
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index e9b683d..92c9206 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -164,15 +164,18 @@
 		if (peer->wps_method == WPS_PBC)
 			methods |= WPS_CONFIG_PUSHBUTTON;
 		else if (peer->wps_method == WPS_PIN_DISPLAY ||
-			 peer->wps_method == WPS_PIN_KEYPAD)
+			 peer->wps_method == WPS_PIN_KEYPAD) {
 			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+			methods |= WPS_CONFIG_P2PS;
+		}
 	} else if (p2p->cfg->config_methods) {
 		methods |= p2p->cfg->config_methods &
 			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
-			 WPS_CONFIG_KEYPAD);
+			 WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
 	} else {
 		methods |= WPS_CONFIG_PUSHBUTTON;
 		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+		methods |= WPS_CONFIG_P2PS;
 	}
 	wpabuf_put_be16(buf, methods);
 
@@ -342,6 +345,256 @@
 }
 
 
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
+{
+	if (!p2p)
+		return;
+
+	/* Service Hash */
+	wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
+	wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+	wpabuf_put_data(buf, p2p->query_hash,
+			p2p->p2ps_seek_count * P2PS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
+		    p2p->query_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+}
+
+
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
+{
+	size_t info_len = 0;
+
+	if (info && info[0])
+		info_len = os_strlen(info);
+
+	/* Session Information Data Info */
+	wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
+	wpabuf_put_le16(buf, (u16) info_len);
+
+	if (info) {
+		wpabuf_put_data(buf, info, info_len);
+		wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
+	}
+}
+
+
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
+{
+	/* Connection Capability Info */
+	wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
+	wpabuf_put_le16(buf, 1);
+	wpabuf_put_u8(buf, connection_cap);
+	wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+		   connection_cap);
+}
+
+
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+	if (!buf || !mac)
+		return;
+
+	/* Advertisement ID Info */
+	wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
+	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+	wpabuf_put_le32(buf, id);
+	wpabuf_put_data(buf, mac, ETH_ALEN);
+	wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
+		   id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+				  u8 hash_count, const u8 *hash,
+				  struct p2ps_advertisement *adv_list)
+{
+	struct p2ps_advertisement *adv;
+	struct wpabuf *tmp_buf;
+	u8 *tag_len = NULL, *ie_len = NULL;
+	size_t svc_len = 0, remaining = 0, total_len = 0;
+
+	if (!adv_list || !hash)
+		return;
+
+	/* Allocate temp buffer, allowing for overflow of 1 instance */
+	tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
+	if (!tmp_buf)
+		return;
+
+	for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
+	     adv = adv->next) {
+		u8 count = hash_count;
+		const u8 *test = hash;
+
+		while (count--) {
+			/* Check for wildcard */
+			if (os_memcmp(test, p2p->wild_card_hash,
+				      P2PS_HASH_LEN) == 0) {
+				total_len = MAX_SVC_ADV_LEN + 1;
+				goto wild_hash;
+			}
+
+			if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
+				goto hash_match;
+
+			test += P2PS_HASH_LEN;
+		}
+
+		/* No matches found - Skip this Adv Instance */
+		continue;
+
+hash_match:
+		if (!tag_len) {
+			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+			remaining = 255 - 4;
+			if (!ie_len) {
+				wpabuf_put_u8(tmp_buf,
+					      P2P_ATTR_ADVERTISED_SERVICE);
+				ie_len = wpabuf_put(tmp_buf, sizeof(u16));
+				remaining -= (sizeof(u8) + sizeof(u16));
+			}
+		}
+
+		svc_len = os_strlen(adv->svc_name);
+
+		if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
+			/* Can't fit... return wildcard */
+			total_len = MAX_SVC_ADV_LEN + 1;
+			break;
+		}
+
+		if (remaining <= (sizeof(adv->id) +
+				  sizeof(adv->config_methods))) {
+			size_t front = remaining;
+			size_t back = (sizeof(adv->id) +
+				       sizeof(adv->config_methods)) - front;
+			u8 holder[sizeof(adv->id) +
+				  sizeof(adv->config_methods)];
+
+			/* This works even if front or back == 0 */
+			WPA_PUT_LE32(holder, adv->id);
+			WPA_PUT_BE16(&holder[sizeof(adv->id)],
+				     adv->config_methods);
+			wpabuf_put_data(tmp_buf, holder, front);
+			p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+			wpabuf_put_data(tmp_buf, &holder[front], back);
+			remaining = 255 - (sizeof(adv->id) +
+					   sizeof(adv->config_methods)) - back;
+		} else {
+			wpabuf_put_le32(tmp_buf, adv->id);
+			wpabuf_put_be16(tmp_buf, adv->config_methods);
+			remaining -= (sizeof(adv->id) +
+				      sizeof(adv->config_methods));
+		}
+
+		/* We are guaranteed at least one byte for svc_len */
+		wpabuf_put_u8(tmp_buf, svc_len);
+		remaining -= sizeof(u8);
+
+		if (remaining < svc_len) {
+			size_t front = remaining;
+			size_t back = svc_len - front;
+
+			wpabuf_put_data(tmp_buf, adv->svc_name, front);
+			p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+			tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+
+			/* In rare cases, we must split across 3 attributes */
+			if (back > 255 - 4) {
+				wpabuf_put_data(tmp_buf,
+						&adv->svc_name[front], 255 - 4);
+				back -= 255 - 4;
+				front += 255 - 4;
+				p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+				tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+			}
+
+			wpabuf_put_data(tmp_buf, &adv->svc_name[front], back);
+			remaining = 255 - 4 - back;
+		} else {
+			wpabuf_put_data(tmp_buf, adv->svc_name, svc_len);
+			remaining -= svc_len;
+		}
+
+		/*           adv_id      config_methods     svc_string */
+		total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
+	}
+
+	if (tag_len)
+		p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+
+	if (ie_len)
+		WPA_PUT_LE16(ie_len, (u16) total_len);
+
+wild_hash:
+	/* If all fit, return matching instances, otherwise the wildcard */
+	if (total_len <= MAX_SVC_ADV_LEN) {
+		wpabuf_put_buf(buf, tmp_buf);
+	} else {
+		char *wild_card = P2PS_WILD_HASH_STR;
+		u8 wild_len;
+
+		/* Insert wildcard instance */
+		tag_len = p2p_buf_add_ie_hdr(buf);
+		wpabuf_put_u8(buf, P2P_ATTR_ADVERTISED_SERVICE);
+		ie_len = wpabuf_put(buf, sizeof(u16));
+
+		wild_len = (u8) os_strlen(wild_card);
+		wpabuf_put_le32(buf, 0);
+		wpabuf_put_be16(buf, 0);
+		wpabuf_put_u8(buf, wild_len);
+		wpabuf_put_data(buf, wild_card, wild_len);
+
+		WPA_PUT_LE16(ie_len, 4 + 2 + 1 + wild_len);
+		p2p_buf_update_ie_hdr(buf, tag_len);
+	}
+
+	wpabuf_free(tmp_buf);
+}
+
+
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+	if (!buf || !mac)
+		return;
+
+	/* Session ID Info */
+	wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
+	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+	wpabuf_put_le32(buf, id);
+	wpabuf_put_data(buf, mac, ETH_ALEN);
+	wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
+		   id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
+{
+	if (!buf || !len || !mask)
+		return;
+
+	/* Feature Capability */
+	wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
+	wpabuf_put_le16(buf, len);
+	wpabuf_put_data(buf, mask, len);
+	wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
+}
+
+
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+				       const u8 *ssid, size_t ssid_len)
+{
+	/* P2P Group ID */
+	wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
+	wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
+	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
+	wpabuf_put_data(buf, ssid, ssid_len);
+	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
+		   MAC2STR(dev_addr));
+}
+
+
 static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
 			      const char *val)
 {
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index c654c5a..98abf9d 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -107,6 +107,8 @@
 		return DEV_PW_PUSHBUTTON;
 	case WPS_NFC:
 		return DEV_PW_NFC_CONNECTION_HANDOVER;
+	case WPS_P2PS:
+		return DEV_PW_P2PS_DEFAULT;
 	default:
 		return DEV_PW_DEFAULT;
 	}
@@ -124,6 +126,8 @@
 		return "PBC";
 	case WPS_NFC:
 		return "NFC";
+	case WPS_P2PS:
+		return "P2PS";
 	default:
 		return "??";
 	}
@@ -218,10 +222,12 @@
 			config_method = WPS_CONFIG_DISPLAY;
 		else if (dev->wps_method == WPS_PBC)
 			config_method = WPS_CONFIG_PUSHBUTTON;
+		else if (dev->wps_method == WPS_P2PS)
+			config_method = WPS_CONFIG_P2PS;
 		else
 			return -1;
 		return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
-					 config_method, 0, 0, 1);
+					 NULL, config_method, 0, 0, 1);
 	}
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
@@ -488,8 +494,8 @@
 }
 
 
-static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
-				 u8 *status)
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+			  u8 *status)
 {
 	struct p2p_channels tmp, intersection;
 
@@ -743,6 +749,16 @@
 				goto fail;
 			}
 			break;
+		case DEV_PW_P2PS_DEFAULT:
+			p2p_dbg(p2p, "Peer using P2PS pin");
+			if (dev->wps_method != WPS_P2PS) {
+				p2p_dbg(p2p,
+					"We have wps_method=%s -> incompatible",
+					p2p_wps_method_str(dev->wps_method));
+				status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+				goto fail;
+			}
+			break;
 		default:
 			if (msg.dev_password_id &&
 			    msg.dev_password_id == dev->oob_pw_id) {
@@ -1102,6 +1118,15 @@
 			goto fail;
 		}
 		break;
+	case DEV_PW_P2PS_DEFAULT:
+		p2p_dbg(p2p, "P2P: Peer using P2PS default pin");
+		if (dev->wps_method != WPS_P2PS) {
+			p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+				p2p_wps_method_str(dev->wps_method));
+			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+			goto fail;
+		}
+		break;
 	default:
 		if (msg.dev_password_id &&
 		    msg.dev_password_id == dev->oob_pw_id) {
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index da8588a..41ca99f 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -981,10 +981,22 @@
 
 unsigned int p2p_get_group_num_members(struct p2p_group *group)
 {
+	if (!group)
+		return 0;
+
 	return group->num_members;
 }
 
 
+int p2p_client_limit_reached(struct p2p_group *group)
+{
+	if (!group || !group->cfg)
+		return 1;
+
+	return group->num_members >= group->cfg->max_clients;
+}
+
+
 const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
 {
 	struct p2p_group_member *iter = *next;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 62711e7..289a62d 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -16,6 +16,13 @@
 
 enum p2p_role_indication;
 
+/*
+ * To force Service Instances to fit within a single P2P Tag, MAX_SVC_ADV_LEN
+ * must equal 248 or less. Must have a minimum size of 19.
+ */
+#define MAX_SVC_ADV_LEN	600
+#define MAX_SVC_ADV_IE_LEN (9 + MAX_SVC_ADV_LEN + (5 * (MAX_SVC_ADV_LEN / 240)))
+
 enum p2p_go_state {
 	UNKNOWN_GO,
 	LOCAL_GO,
@@ -64,7 +71,7 @@
 	char country[3];
 	struct p2p_channels channels;
 	int oper_freq;
-	u8 oper_ssid[32];
+	u8 oper_ssid[SSID_MAX_LEN];
 	size_t oper_ssid_len;
 
 	/**
@@ -98,6 +105,8 @@
 #define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
 #define P2P_DEV_NO_PREF_CHAN BIT(18)
 #define P2P_DEV_WAIT_INV_REQ_ACK BIT(19)
+#define P2P_DEV_P2PS_REPORTED BIT(20)
+#define P2P_DEV_PD_PEER_P2PS BIT(21)
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -313,7 +322,7 @@
 	/**
 	 * ssid - Selected SSID for GO Negotiation (if local end will be GO)
 	 */
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 
 	/**
 	 * ssid_len - ssid length in octets
@@ -354,6 +363,7 @@
 		P2P_PENDING_GO_NEG_CONFIRM,
 		P2P_PENDING_SD,
 		P2P_PENDING_PD,
+		P2P_PENDING_PD_RESPONSE,
 		P2P_PENDING_INVITATION_REQUEST,
 		P2P_PENDING_INVITATION_RESPONSE,
 		P2P_PENDING_DEV_DISC_REQUEST,
@@ -393,7 +403,7 @@
 	enum p2p_invite_role inv_role;
 	u8 inv_bssid[ETH_ALEN];
 	int inv_bssid_set;
-	u8 inv_ssid[32];
+	u8 inv_ssid[SSID_MAX_LEN];
 	size_t inv_ssid_len;
 	u8 inv_sa[ETH_ALEN];
 	u8 inv_group_bssid[ETH_ALEN];
@@ -492,6 +502,16 @@
 	u8 pending_channel;
 	u8 pending_channel_forced;
 
+	/* ASP Support */
+	struct p2ps_advertisement *p2ps_adv_list;
+	struct p2ps_provision *p2ps_prov;
+	u8 wild_card_hash[P2PS_HASH_LEN];
+	u8 query_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
+	u8 query_count;
+	u8 p2ps_seek;
+	u8 p2ps_seek_count;
+	u8 p2ps_svc_found;
+
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie_beacon;
 	struct wpabuf *wfd_ie_probe_req;
@@ -558,7 +578,7 @@
 	const u8 *p2p_device_addr;
 	const u8 *pri_dev_type;
 	u8 num_sec_dev_types;
-	char device_name[33];
+	char device_name[WPS_DEV_NAME_MAX_LEN + 1];
 	u16 config_methods;
 
 	/* WPS IE */
@@ -586,6 +606,31 @@
 
 	/* SSID IE */
 	const u8 *ssid;
+
+	/* P2PS */
+	u8 service_hash_count;
+	const u8 *service_hash;
+
+	const u8 *session_info;
+	size_t session_info_len;
+
+	const u8 *conn_cap;
+
+	const u8 *adv_id;
+	const u8 *adv_mac;
+
+	const u8 *adv_service_instance;
+	size_t adv_service_instance_len;
+
+	const u8 *session_id;
+	const u8 *session_mac;
+
+	const u8 *feature_cap;
+	size_t feature_cap_len;
+
+	const u8 *persistent_dev;
+	const u8 *persistent_ssid;
+	size_t persistent_ssid_len;
 };
 
 
@@ -698,6 +743,18 @@
 void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
 				    u8 oper_class, u8 channel,
 				    enum p2p_role_indication role);
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p);
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info);
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap);
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+				  u8 count, const u8 *hash,
+				  struct p2ps_advertisement *adv_list);
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len,
+				    const u8 *mask);
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+				       const u8 *ssid, size_t ssid_len);
 int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
 		     int all_attr);
 
@@ -793,6 +850,8 @@
 			unsigned int force_freq, unsigned int pref_freq,
 			int go);
 void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+			  u8 *status);
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
 void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 558c6dd..44a6bbf 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -387,7 +387,7 @@
 	} else
 		p2p->inv_group_bssid_ptr = NULL;
 	if (msg.group_id) {
-		if (msg.group_id_len - ETH_ALEN <= 32) {
+		if (msg.group_id_len - ETH_ALEN <= SSID_MAX_LEN) {
 			os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
 				  msg.group_id_len - ETH_ALEN);
 			p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index 52ba19e..980dddf 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -149,7 +149,8 @@
 		pos += 2;
 		nlen = WPA_GET_BE16(pos);
 		pos += 2;
-		if (data + len - pos < (int) nlen || nlen > 32) {
+		if (data + len - pos < (int) nlen ||
+		    nlen > WPS_DEV_NAME_MAX_LEN) {
 			wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
 				   "length %d (buf len %d)", (int) nlen,
 				   (int) (data + len - pos));
@@ -160,8 +161,7 @@
 		for (i = 0; i < nlen; i++) {
 			if (msg->device_name[i] == '\0')
 				break;
-			if (msg->device_name[i] > 0 &&
-			    msg->device_name[i] < 32)
+			if (is_ctrl_char(msg->device_name[i]))
 				msg->device_name[i] = '_';
 		}
 		wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
@@ -203,7 +203,7 @@
 			   MAC2STR(msg->group_bssid));
 		break;
 	case P2P_ATTR_GROUP_ID:
-		if (len < ETH_ALEN || len > ETH_ALEN + 32) {
+		if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
 			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID "
 				   "attribute length %d", len);
 			return -1;
@@ -281,6 +281,112 @@
 			   data[0], data[1], data[2], data[3], data[4],
 			   data[5]);
 		break;
+	case P2P_ATTR_SERVICE_HASH:
+		if (len < P2PS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Service Hash (length %u)",
+				   len);
+			return -1;
+		}
+		msg->service_hash_count = len / P2PS_HASH_LEN;
+		msg->service_hash = data;
+		wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len);
+		break;
+	case P2P_ATTR_SESSION_INFORMATION_DATA:
+		msg->session_info = data;
+		msg->session_info_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p",
+			   len, data);
+		break;
+	case P2P_ATTR_CONNECTION_CAPABILITY:
+		if (len < 1) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Connection Capability (length %u)",
+				   len);
+			return -1;
+		}
+		msg->conn_cap = data;
+		wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+			   *msg->conn_cap);
+		break;
+	case P2P_ATTR_ADVERTISEMENT_ID:
+		if (len < 10) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Advertisement ID (length %u)",
+				   len);
+			return -1;
+		}
+		msg->adv_id = data;
+		msg->adv_mac = &data[sizeof(u32)];
+		wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x",
+			   WPA_GET_LE32(data));
+		break;
+	case P2P_ATTR_ADVERTISED_SERVICE:
+		if (len < 8) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Service Instance (length %u)",
+				   len);
+			return -1;
+		}
+		msg->adv_service_instance = data;
+		msg->adv_service_instance_len = len;
+		if (len <= 255 + 8) {
+			char str[256];
+			u8 namelen;
+
+			namelen = data[6];
+			if (namelen > len - 7)
+				break;
+			os_memcpy(str, &data[7], namelen);
+			str[namelen] = '\0';
+			wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s",
+				   WPA_GET_LE32(data), str);
+		} else {
+			wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p",
+				   data);
+		}
+		break;
+	case P2P_ATTR_SESSION_ID:
+		if (len < sizeof(u32) + ETH_ALEN) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Session ID Info (length %u)",
+				   len);
+			return -1;
+		}
+		msg->session_id = data;
+		msg->session_mac = &data[sizeof(u32)];
+		wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR,
+			   WPA_GET_LE32(data), MAC2STR(msg->session_mac));
+		break;
+	case P2P_ATTR_FEATURE_CAPABILITY:
+		if (!len) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Too short Feature Capability (length %u)",
+				   len);
+			return -1;
+		}
+		msg->feature_cap = data;
+		msg->feature_cap_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len);
+		break;
+	case P2P_ATTR_PERSISTENT_GROUP:
+	{
+		if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: Invalid Persistent Group Info (length %u)",
+				   len);
+			return -1;
+		}
+
+		msg->persistent_dev = data;
+		msg->persistent_ssid_len = len - ETH_ALEN;
+		msg->persistent_ssid = &data[ETH_ALEN];
+		wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s",
+			   MAC2STR(msg->persistent_dev),
+			   wpa_ssid_txt(msg->persistent_ssid,
+					msg->persistent_ssid_len));
+		break;
+	}
 	default:
 		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
 			   "(length %d)", id, len);
@@ -410,7 +516,7 @@
 	struct ieee802_11_elems elems;
 
 	ieee802_11_parse_elems(data, len, &elems, 0);
-	if (elems.ds_params && elems.ds_params_len >= 1)
+	if (elems.ds_params)
 		msg->ds_params = elems.ds_params;
 	if (elems.ssid)
 		msg->ssid = elems.ssid - 2;
@@ -568,8 +674,8 @@
 		t += 2;
 		if (count > cend - t)
 			return -1; /* invalid Device Name TLV */
-		if (count >= 32)
-			count = 32;
+		if (count >= WPS_DEV_NAME_MAX_LEN)
+			count = WPS_DEV_NAME_MAX_LEN;
 		cli->dev_name = (const char *) t;
 		cli->dev_name_len = count;
 
@@ -597,7 +703,7 @@
 
 	for (i = 0; i < info.num_clients; i++) {
 		struct p2p_client_info *cli;
-		char name[33];
+		char name[WPS_DEV_NAME_MAX_LEN + 1];
 		char devtype[WPS_DEV_TYPE_BUFSIZE];
 		u8 s;
 		int count;
@@ -636,7 +742,7 @@
 		name[cli->dev_name_len] = '\0';
 		count = (int) cli->dev_name_len - 1;
 		while (count >= 0) {
-			if (name[count] > 0 && name[count] < 32)
+			if (is_ctrl_char(name[count]))
 				name[count] = '_';
 			count--;
 		}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e101367..bc84269 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -40,14 +40,132 @@
 }
 
 
+static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf)
+{
+	int found;
+	u8 intended_addr[ETH_ALEN];
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+	int group_iface;
+
+	if (!p2p->cfg->get_go_info)
+		return;
+
+	found = p2p->cfg->get_go_info(
+		p2p->cfg->cb_ctx, intended_addr, ssid,
+		&ssid_len, &group_iface);
+	if (found) {
+		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+				     ssid, ssid_len);
+		p2p_buf_add_intended_addr(buf, intended_addr);
+	} else {
+		if (!p2p->ssid_set) {
+			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+			p2p->ssid_set = 1;
+		}
+
+		/* Add pre-composed P2P Group ID */
+		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+				     p2p->ssid, p2p->ssid_len);
+
+		if (group_iface)
+			p2p_buf_add_intended_addr(
+				buf, p2p->intended_addr);
+		else
+			p2p_buf_add_intended_addr(
+				buf, p2p->cfg->dev_addr);
+	}
+}
+
+
+static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
+				  struct wpabuf *buf, u16 config_methods)
+{
+	struct p2ps_provision *prov = p2p->p2ps_prov;
+	u8 feat_cap_mask[] = { 1, 0 };
+	int shared_group = 0;
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+	u8 go_dev_addr[ETH_ALEN];
+
+	/* If we might be explicite group owner, add GO details */
+	if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
+			     P2PS_SETUP_NEW))
+		p2ps_add_new_group_info(p2p, buf);
+
+	if (prov->status >= 0)
+		p2p_buf_add_status(buf, (u8) prov->status);
+	else
+		prov->method = config_methods;
+
+	if (p2p->cfg->get_persistent_group) {
+		shared_group = p2p->cfg->get_persistent_group(
+			p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0,
+			go_dev_addr, ssid, &ssid_len);
+	}
+
+	/* Add Operating Channel if conncap includes GO */
+	if (shared_group ||
+	    (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
+			      P2PS_SETUP_NEW))) {
+		u8 tmp;
+
+		p2p_go_select_channel(p2p, dev, &tmp);
+
+		if (p2p->op_reg_class && p2p->op_channel)
+			p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+						      p2p->op_reg_class,
+						      p2p->op_channel);
+		else
+			p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+						      p2p->cfg->op_reg_class,
+						      p2p->cfg->op_channel);
+	}
+
+	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels);
+
+	if (prov->info[0])
+		p2p_buf_add_session_info(buf, prov->info);
+
+	p2p_buf_add_connection_capability(buf, prov->conncap);
+
+	p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
+
+	if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
+	    prov->conncap ==
+	    (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
+	    prov->conncap ==
+	    (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
+		/* Add Config Timeout */
+		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);
+
+	p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
+
+	p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+				       feat_cap_mask);
+
+	if (shared_group)
+		p2p_buf_add_persistent_group_info(buf, go_dev_addr,
+						  ssid, ssid_len);
+}
+
+
 static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
-					       u8 dialog_token,
-					       u16 config_methods,
-					       struct p2p_device *go)
+					       struct p2p_device *dev,
+					       int join)
 {
 	struct wpabuf *buf;
 	u8 *len;
 	size_t extra = 0;
+	u8 dialog_token = dev->dialog_token;
+	u16 config_methods = dev->req_config_methods;
+	struct p2p_device *go = join ? dev : NULL;
+	u8 group_capab;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_prov_disc_req)
@@ -57,6 +175,10 @@
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
 
+	if (p2p->p2ps_prov)
+		extra += os_strlen(p2p->p2ps_prov->info) + 1 +
+			sizeof(struct p2ps_provision);
+
 	buf = wpabuf_alloc(1000 + extra);
 	if (buf == NULL)
 		return NULL;
@@ -64,10 +186,23 @@
 	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
 
 	len = p2p_buf_add_ie_hdr(buf);
+
+	group_capab = 0;
+	if (p2p->p2ps_prov) {
+		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		if (p2p->cross_connect)
+			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+		if (p2p->cfg->p2p_intra_bss)
+			group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+	}
 	p2p_buf_add_capability(buf, p2p->dev_capab &
-			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+			       group_capab);
 	p2p_buf_add_device_info(buf, p2p, NULL);
-	if (go) {
+	if (p2p->p2ps_prov) {
+		p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
+	} else if (go) {
 		p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
 				     go->oper_ssid, go->oper_ssid_len);
 	}
@@ -89,13 +224,19 @@
 
 
 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
+						struct p2p_device *dev,
 						u8 dialog_token,
+						enum p2p_status_code status,
 						u16 config_methods,
+						u32 adv_id,
 						const u8 *group_id,
-						size_t group_id_len)
+						size_t group_id_len,
+						const u8 *persist_ssid,
+						size_t persist_ssid_len)
 {
 	struct wpabuf *buf;
 	size_t extra = 0;
+	int persist = 0;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
@@ -121,12 +262,103 @@
 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
 
-	buf = wpabuf_alloc(100 + extra);
+	buf = wpabuf_alloc(1000 + extra);
 	if (buf == NULL)
 		return NULL;
 
 	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
 
+	/* Add P2P IE for P2PS */
+	if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
+		u8 feat_cap_mask[] = { 1, 0 };
+		u8 *len = p2p_buf_add_ie_hdr(buf);
+		struct p2ps_provision *prov = p2p->p2ps_prov;
+		u8 group_capab;
+
+		if (!status && prov->status != -1)
+			status = prov->status;
+
+		p2p_buf_add_status(buf, status);
+		group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
+			P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		if (p2p->cross_connect)
+			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+		if (p2p->cfg->p2p_intra_bss)
+			group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+		p2p_buf_add_capability(buf, p2p->dev_capab &
+				       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+				       group_capab);
+		p2p_buf_add_device_info(buf, p2p, NULL);
+
+		if (persist_ssid && p2p->cfg->get_persistent_group &&
+		    (status == P2P_SC_SUCCESS ||
+		     status == P2P_SC_SUCCESS_DEFERRED)) {
+			u8 ssid[SSID_MAX_LEN];
+			size_t ssid_len;
+			u8 go_dev_addr[ETH_ALEN];
+
+			persist = p2p->cfg->get_persistent_group(
+				p2p->cfg->cb_ctx,
+				dev->info.p2p_device_addr,
+				persist_ssid, persist_ssid_len, go_dev_addr,
+				ssid, &ssid_len);
+			if (persist)
+				p2p_buf_add_persistent_group_info(
+					buf, go_dev_addr, ssid, ssid_len);
+		}
+
+		if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
+			p2ps_add_new_group_info(p2p, buf);
+
+		/* Add Operating Channel if conncap indicates GO */
+		if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) {
+			u8 tmp;
+
+			if (dev)
+				p2p_go_select_channel(p2p, dev, &tmp);
+
+			if (p2p->op_reg_class && p2p->op_channel)
+				p2p_buf_add_operating_channel(
+					buf, p2p->cfg->country,
+					p2p->op_reg_class,
+					p2p->op_channel);
+			else
+				p2p_buf_add_operating_channel(
+					buf, p2p->cfg->country,
+					p2p->cfg->op_reg_class,
+					p2p->cfg->op_channel);
+		}
+
+		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+					 &p2p->cfg->channels);
+
+		if (!persist && (status == P2P_SC_SUCCESS ||
+				 status == P2P_SC_SUCCESS_DEFERRED))
+			p2p_buf_add_connection_capability(buf, prov->conncap);
+
+		p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
+
+		p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+					   p2p->client_timeout);
+
+		p2p_buf_add_session_id(buf, prov->session_id,
+				       prov->session_mac);
+
+		p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+					       feat_cap_mask);
+		p2p_buf_update_ie_hdr(buf, len);
+	} else if (status != P2P_SC_SUCCESS || adv_id) {
+		u8 *len = p2p_buf_add_ie_hdr(buf);
+
+		p2p_buf_add_status(buf, status);
+
+		if (p2p->p2ps_prov)
+			p2p_buf_add_advertisement_id(buf, adv_id,
+						     p2p->p2ps_prov->adv_mac);
+
+		p2p_buf_update_ie_hdr(buf, len);
+	}
+
 	/* WPS IE with Config Methods attribute */
 	p2p_build_wps_ie_config_methods(buf, config_methods);
 
@@ -142,14 +374,50 @@
 }
 
 
+static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
+				u32 session_id, u16 method,
+				const u8 *session_mac, const u8 *adv_mac)
+{
+	struct p2ps_provision *tmp;
+
+	if (!p2p->p2ps_prov) {
+		p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
+		if (!p2p->p2ps_prov)
+			return -1;
+	} else {
+		os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
+	}
+
+	tmp = p2p->p2ps_prov;
+	tmp->adv_id = adv_id;
+	tmp->session_id = session_id;
+	tmp->method = method;
+	os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
+	os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
+	tmp->info[0] = '\0';
+
+	return 0;
+}
+
+
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 			       const u8 *data, size_t len, int rx_freq)
 {
 	struct p2p_message msg;
 	struct p2p_device *dev;
 	int freq;
-	int reject = 1;
+	enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
 	struct wpabuf *resp;
+	u32 adv_id = 0;
+	struct p2ps_advertisement *p2ps_adv = NULL;
+	u8 conncap = P2PS_SETUP_NEW;
+	u8 auto_accept = 0;
+	u32 session_id = 0;
+	u8 session_mac[ETH_ALEN];
+	u8 adv_mac[ETH_ALEN];
+	u8 group_mac[ETH_ALEN];
+	int passwd_id = DEV_PW_DEFAULT;
+	u16 config_methods;
 
 	if (p2p_parse(data, len, &msg))
 		return;
@@ -175,12 +443,13 @@
 
 	if (!(msg.wps_config_methods &
 	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
-	       WPS_CONFIG_PUSHBUTTON))) {
+	       WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_P2PS))) {
 		p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
 		goto out;
 	}
 
-	if (msg.group_id) {
+	/* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
+	if (!msg.adv_id && msg.group_id) {
 		size_t i;
 		for (i = 0; i < p2p->num_groups; i++) {
 			if (p2p_group_is_group_id_match(p2p->groups[i],
@@ -194,28 +463,203 @@
 		}
 	}
 
-	if (dev)
+	if (dev) {
 		dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
-				P2P_DEV_PD_PEER_KEYPAD);
+				P2P_DEV_PD_PEER_KEYPAD |
+				P2P_DEV_PD_PEER_P2PS);
+
+		/* Remove stale persistent groups */
+		if (p2p->cfg->remove_stale_groups) {
+			p2p->cfg->remove_stale_groups(
+				p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+				msg.persistent_dev,
+				msg.persistent_ssid, msg.persistent_ssid_len);
+		}
+	}
 	if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
 		p2p_dbg(p2p, "Peer " MACSTR
 			" requested us to show a PIN on display", MAC2STR(sa));
 		if (dev)
 			dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+		passwd_id = DEV_PW_USER_SPECIFIED;
 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
 		p2p_dbg(p2p, "Peer " MACSTR
 			" requested us to write its PIN using keypad",
 			MAC2STR(sa));
 		if (dev)
 			dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+		passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
+	} else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+		p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
+			MAC2STR(sa));
+		if (dev)
+			dev->flags |= P2P_DEV_PD_PEER_P2PS;
+		passwd_id = DEV_PW_P2PS_DEFAULT;
 	}
 
-	reject = 0;
+	reject = P2P_SC_SUCCESS;
+
+	os_memset(session_mac, 0, ETH_ALEN);
+	os_memset(adv_mac, 0, ETH_ALEN);
+	os_memset(group_mac, 0, ETH_ALEN);
+
+	if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
+	    (msg.status || msg.conn_cap)) {
+		u8 remote_conncap;
+
+		if (msg.intended_addr)
+			os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+
+		os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
+		os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+
+		session_id = WPA_GET_LE32(msg.session_id);
+		adv_id = WPA_GET_LE32(msg.adv_id);
+
+		if (!msg.status)
+			p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+
+		p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+
+		if (msg.conn_cap)
+			conncap = *msg.conn_cap;
+		remote_conncap = conncap;
+
+		if (p2ps_adv) {
+			auto_accept = p2ps_adv->auto_accept;
+			conncap = p2p->cfg->p2ps_group_capability(
+				p2p->cfg->cb_ctx, conncap, auto_accept);
+
+			p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
+				auto_accept, remote_conncap, conncap);
+
+			if (p2ps_adv->config_methods &&
+			    !(msg.wps_config_methods &
+			      p2ps_adv->config_methods)) {
+				p2p_dbg(p2p,
+					"Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
+					p2ps_adv->config_methods,
+					msg.wps_config_methods);
+				reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+			} else if (!p2ps_adv->state) {
+				p2p_dbg(p2p, "P2PS state unavailable");
+				reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+			} else if (!conncap) {
+				p2p_dbg(p2p, "Conncap resolution failed");
+				reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+			}
+
+			if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+				p2p_dbg(p2p, "Keypad - always defer");
+				auto_accept = 0;
+			}
+
+			if (auto_accept || reject != P2P_SC_SUCCESS) {
+				struct p2ps_provision *tmp;
+
+				if (reject == P2P_SC_SUCCESS && !conncap) {
+					reject =
+						P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+				}
+
+				if (p2ps_setup_p2ps_prov(
+					    p2p, adv_id, session_id,
+					    msg.wps_config_methods,
+					    session_mac, adv_mac) < 0) {
+					reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+					goto out;
+				}
+
+				tmp = p2p->p2ps_prov;
+				if (conncap) {
+					tmp->conncap = conncap;
+					tmp->status = P2P_SC_SUCCESS;
+				} else {
+					tmp->conncap = auto_accept;
+					tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+				}
+
+				if (reject != P2P_SC_SUCCESS)
+					goto out;
+			}
+		} else if (!msg.status) {
+			reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+			goto out;
+		}
+
+		if (!msg.status && !auto_accept &&
+		    (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+			struct p2ps_provision *tmp;
+
+			if (!conncap) {
+				reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+				goto out;
+			}
+
+			if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
+						 msg.wps_config_methods,
+						 session_mac, adv_mac) < 0) {
+				reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+				goto out;
+			}
+			tmp = p2p->p2ps_prov;
+			reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+			tmp->status = reject;
+		}
+
+		if (msg.status) {
+			if (*msg.status &&
+			    *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+				reject = *msg.status;
+			} else if (*msg.status == P2P_SC_SUCCESS_DEFERRED &&
+				   p2p->p2ps_prov) {
+				u16 method = p2p->p2ps_prov->method;
+
+				conncap = p2p->cfg->p2ps_group_capability(
+					p2p->cfg->cb_ctx, remote_conncap,
+					p2p->p2ps_prov->conncap);
+
+				p2p_dbg(p2p,
+					"Conncap: local:%d remote:%d result:%d",
+					p2p->p2ps_prov->conncap,
+					remote_conncap, conncap);
+
+				/*
+				 * Ensure that if we asked for PIN originally,
+				 * our method is consistent with original
+				 * request.
+				 */
+				if (method & WPS_CONFIG_DISPLAY)
+					method = WPS_CONFIG_KEYPAD;
+				else if (method & WPS_CONFIG_KEYPAD)
+					method = WPS_CONFIG_DISPLAY;
+
+				/* Reject this "Deferred Accept* if incompatible
+				 * conncap or method */
+				if (!conncap ||
+				    !(msg.wps_config_methods & method))
+					reject =
+						P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+				else
+					reject = P2P_SC_SUCCESS;
+
+				p2p->p2ps_prov->status = reject;
+				p2p->p2ps_prov->conncap = conncap;
+			}
+		}
+	}
 
 out:
-	resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
-					reject ? 0 : msg.wps_config_methods,
-					msg.group_id, msg.group_id_len);
+	if (reject == P2P_SC_SUCCESS ||
+	    reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+		config_methods = msg.wps_config_methods;
+	else
+		config_methods = 0;
+	resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject,
+					config_methods, adv_id,
+					msg.group_id, msg.group_id_len,
+					msg.persistent_ssid,
+					msg.persistent_ssid_len);
 	if (resp == NULL) {
 		p2p_parse_free(&msg);
 		return;
@@ -232,7 +676,7 @@
 		p2p_parse_free(&msg);
 		return;
 	}
-	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+	p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
@@ -242,7 +686,91 @@
 
 	wpabuf_free(resp);
 
-	if (!reject && p2p->cfg->prov_disc_req) {
+	if (!p2p->cfg->p2ps_prov_complete) {
+		/* Don't emit anything */
+	} else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
+		   *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+		reject = *msg.status;
+		p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+					     sa, adv_mac, session_mac,
+					     NULL, adv_id, session_id,
+					     0, 0, msg.persistent_ssid,
+					     msg.persistent_ssid_len,
+					     0, 0, NULL);
+	} else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+		   p2p->p2ps_prov) {
+		p2p->p2ps_prov->status = reject;
+		p2p->p2ps_prov->conncap = conncap;
+
+		if (reject != P2P_SC_SUCCESS)
+			p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+						     sa, adv_mac, session_mac,
+						     NULL, adv_id,
+						     session_id, conncap, 0,
+						     msg.persistent_ssid,
+						     msg.persistent_ssid_len, 0,
+						     0, NULL);
+		else
+			p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
+						     *msg.status,
+						     sa, adv_mac, session_mac,
+						     group_mac, adv_id,
+						     session_id, conncap,
+						     passwd_id,
+						     msg.persistent_ssid,
+						     msg.persistent_ssid_len, 0,
+						     0, NULL);
+	} else if (msg.status && p2p->p2ps_prov) {
+		p2p->p2ps_prov->status = P2P_SC_SUCCESS;
+		p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
+					     adv_mac, session_mac, group_mac,
+					     adv_id, session_id, conncap,
+					     passwd_id,
+					     msg.persistent_ssid,
+					     msg.persistent_ssid_len,
+					     0, 0, NULL);
+	} else if (msg.status) {
+	} else if (auto_accept && reject == P2P_SC_SUCCESS) {
+		p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+					     sa, adv_mac, session_mac,
+					     group_mac, adv_id, session_id,
+					     conncap, passwd_id,
+					     msg.persistent_ssid,
+					     msg.persistent_ssid_len,
+					     0, 0, NULL);
+	} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+		   (!msg.session_info || !msg.session_info_len)) {
+		p2p->p2ps_prov->method = msg.wps_config_methods;
+
+		p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+					     sa, adv_mac, session_mac,
+					     group_mac, adv_id, session_id,
+					     conncap, passwd_id,
+					     msg.persistent_ssid,
+					     msg.persistent_ssid_len,
+					     0, 1, NULL);
+	} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+		size_t buf_len = msg.session_info_len;
+		char *buf = os_malloc(2 * buf_len + 1);
+
+		if (buf) {
+			p2p->p2ps_prov->method = msg.wps_config_methods;
+
+			utf8_escape((char *) msg.session_info, buf_len,
+				    buf, 2 * buf_len + 1);
+
+			p2p->cfg->p2ps_prov_complete(
+				p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
+				adv_mac, session_mac, group_mac, adv_id,
+				session_id, conncap, passwd_id,
+				msg.persistent_ssid, msg.persistent_ssid_len,
+				0, 1, buf);
+
+			os_free(buf);
+		}
+	}
+
+	if (reject == P2P_SC_SUCCESS && p2p->cfg->prov_disc_req) {
 		const u8 *dev_addr = sa;
 		if (msg.p2p_device_addr)
 			dev_addr = msg.p2p_device_addr;
@@ -265,11 +793,48 @@
 	struct p2p_message msg;
 	struct p2p_device *dev;
 	u16 report_config_methods = 0, req_config_methods;
+	u8 status = P2P_SC_SUCCESS;
 	int success = 0;
+	u32 adv_id = 0;
+	u8 conncap = P2PS_SETUP_NEW;
+	u8 adv_mac[ETH_ALEN];
+	u8 group_mac[ETH_ALEN];
+	int passwd_id = DEV_PW_DEFAULT;
 
 	if (p2p_parse(data, len, &msg))
 		return;
 
+	/* Parse the P2PS members present */
+	if (msg.status)
+		status = *msg.status;
+
+	if (msg.intended_addr)
+		os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+	else
+		os_memset(group_mac, 0, ETH_ALEN);
+
+	if (msg.adv_mac)
+		os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+	else
+		os_memset(adv_mac, 0, ETH_ALEN);
+
+	if (msg.adv_id)
+		adv_id = WPA_GET_LE32(msg.adv_id);
+
+	if (msg.conn_cap) {
+		conncap = *msg.conn_cap;
+
+		/* Switch bits to local relative */
+		switch (conncap) {
+		case P2PS_SETUP_GROUP_OWNER:
+			conncap = P2PS_SETUP_CLIENT;
+			break;
+		case P2PS_SETUP_CLIENT:
+			conncap = P2PS_SETUP_GROUP_OWNER;
+			break;
+		}
+	}
+
 	p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
 		" with config methods 0x%x",
 		MAC2STR(sa), msg.wps_config_methods);
@@ -313,23 +878,109 @@
 			msg.wps_config_methods, req_config_methods);
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
-						 P2P_PROV_DISC_REJECTED);
+						 P2P_PROV_DISC_REJECTED,
+						 adv_id, adv_mac, NULL);
 		p2p_parse_free(&msg);
+		os_free(p2p->p2ps_prov);
+		p2p->p2ps_prov = NULL;
 		goto out;
 	}
 
 	report_config_methods = req_config_methods;
 	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
-			P2P_DEV_PD_PEER_KEYPAD);
+			P2P_DEV_PD_PEER_KEYPAD |
+			P2P_DEV_PD_PEER_P2PS);
 	if (req_config_methods & WPS_CONFIG_DISPLAY) {
 		p2p_dbg(p2p, "Peer " MACSTR
 			" accepted to show a PIN on display", MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+		passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
 		p2p_dbg(p2p, "Peer " MACSTR
 			" accepted to write our PIN using keypad",
 			MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+		passwd_id = DEV_PW_USER_SPECIFIED;
+	} else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+		p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
+			MAC2STR(sa));
+		dev->flags |= P2P_DEV_PD_PEER_P2PS;
+		passwd_id = DEV_PW_P2PS_DEFAULT;
+	}
+
+	if ((msg.conn_cap || msg.persistent_dev) &&
+	    msg.adv_id &&
+	    (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+	    p2p->p2ps_prov) {
+		if (p2p->cfg->p2ps_prov_complete) {
+			p2p->cfg->p2ps_prov_complete(
+				p2p->cfg->cb_ctx, status, sa, adv_mac,
+				p2p->p2ps_prov->session_mac,
+				group_mac, adv_id, p2p->p2ps_prov->session_id,
+				conncap, passwd_id, msg.persistent_ssid,
+				msg.persistent_ssid_len, 1, 0, NULL);
+		}
+		os_free(p2p->p2ps_prov);
+		p2p->p2ps_prov = NULL;
+	}
+
+	if (status != P2P_SC_SUCCESS &&
+	    status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+	    status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
+		if (p2p->cfg->p2ps_prov_complete)
+			p2p->cfg->p2ps_prov_complete(
+				p2p->cfg->cb_ctx, status, sa, adv_mac,
+				p2p->p2ps_prov->session_mac,
+				group_mac, adv_id, p2p->p2ps_prov->session_id,
+				0, 0, NULL, 0, 1, 0, NULL);
+		os_free(p2p->p2ps_prov);
+		p2p->p2ps_prov = NULL;
+	}
+
+	if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+		if (p2p->cfg->remove_stale_groups) {
+			p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
+						      dev->info.p2p_device_addr,
+						      NULL, NULL, 0);
+		}
+
+		if (msg.session_info && msg.session_info_len) {
+			size_t info_len = msg.session_info_len;
+			char *deferred_sess_resp = os_malloc(2 * info_len + 1);
+
+			if (!deferred_sess_resp) {
+				p2p_parse_free(&msg);
+				os_free(p2p->p2ps_prov);
+				p2p->p2ps_prov = NULL;
+				goto out;
+			}
+			utf8_escape((char *) msg.session_info, info_len,
+				    deferred_sess_resp, 2 * info_len + 1);
+
+			if (p2p->cfg->prov_disc_fail)
+				p2p->cfg->prov_disc_fail(
+					p2p->cfg->cb_ctx, sa,
+					P2P_PROV_DISC_INFO_UNAVAILABLE,
+					adv_id, adv_mac,
+					deferred_sess_resp);
+			os_free(deferred_sess_resp);
+		} else
+			if (p2p->cfg->prov_disc_fail)
+				p2p->cfg->prov_disc_fail(
+					p2p->cfg->cb_ctx, sa,
+					P2P_PROV_DISC_INFO_UNAVAILABLE,
+					adv_id, adv_mac, NULL);
+	} else if (msg.wps_config_methods != dev->req_config_methods ||
+		   status != P2P_SC_SUCCESS) {
+		p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+						 P2P_PROV_DISC_REJECTED, 0,
+						 NULL, NULL);
+		p2p_parse_free(&msg);
+		os_free(p2p->p2ps_prov);
+		p2p->p2ps_prov = NULL;
+		goto out;
 	}
 
 	/* Store the provisioning info */
@@ -388,9 +1039,33 @@
 		/* TODO: use device discoverability request through GO */
 	}
 
-	req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
-				      dev->req_config_methods,
-				      join ? dev : NULL);
+	if (p2p->p2ps_prov) {
+		if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
+			if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
+				dev->req_config_methods = WPS_CONFIG_KEYPAD;
+			else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
+				dev->req_config_methods = WPS_CONFIG_DISPLAY;
+			else
+				dev->req_config_methods = WPS_CONFIG_P2PS;
+		} else {
+			/* Order of preference, based on peer's capabilities */
+			if (p2p->p2ps_prov->method)
+				dev->req_config_methods =
+					p2p->p2ps_prov->method;
+			else if (dev->info.config_methods & WPS_CONFIG_P2PS)
+				dev->req_config_methods = WPS_CONFIG_P2PS;
+			else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
+				dev->req_config_methods = WPS_CONFIG_DISPLAY;
+			else
+				dev->req_config_methods = WPS_CONFIG_KEYPAD;
+		}
+		p2p_dbg(p2p,
+			"Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
+			p2p->p2ps_prov->method, p2p->p2ps_prov->status,
+			dev->req_config_methods);
+	}
+
+	req = p2p_build_prov_disc_req(p2p, dev, join);
 	if (req == NULL)
 		return -1;
 
@@ -413,6 +1088,7 @@
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
+		      struct p2ps_provision *p2ps_prov,
 		      u16 config_methods, int join, int force_freq,
 		      int user_initiated_pd)
 {
@@ -424,17 +1100,28 @@
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
 			" not yet known", MAC2STR(peer_addr));
+		os_free(p2ps_prov);
 		return -1;
 	}
 
 	p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
 		" (config methods 0x%x)",
 		MAC2STR(peer_addr), config_methods);
-	if (config_methods == 0)
+	if (config_methods == 0 && !p2ps_prov) {
+		os_free(p2ps_prov);
 		return -1;
+	}
+
+	if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
+	    p2p->p2ps_prov) {
+		/* Use cached method from deferred provisioning */
+		p2ps_prov->method = p2p->p2ps_prov->method;
+	}
 
 	/* Reset provisioning info */
 	dev->wps_prov_info = 0;
+	os_free(p2p->p2ps_prov);
+	p2p->p2ps_prov = p2ps_prov;
 
 	dev->req_config_methods = config_methods;
 	if (join)
diff --git a/src/radius/Makefile b/src/radius/Makefile
index b5d063d..3ad4751 100644
--- a/src/radius/Makefile
+++ b/src/radius/Makefile
@@ -14,6 +14,7 @@
 LIB_OBJS= \
 	radius.o \
 	radius_client.o \
+	radius_das.o \
 	radius_server.o
 
 libradius.a: $(LIB_OBJS)
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 6eba2eb..2c01b3f 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -993,13 +993,16 @@
 
 	/* key: 16-bit salt followed by encrypted key info */
 
-	if (len < 2 + 16)
+	if (len < 2 + 16) {
+		wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d",
+			   __func__, (int) len);
 		return NULL;
+	}
 
 	pos = key + 2;
 	left = len - 2;
 	if (left % 16) {
-		wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+		wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu",
 			   (unsigned long) left);
 		return NULL;
 	}
@@ -1034,7 +1037,7 @@
 	}
 
 	if (plain[0] == 0 || plain[0] > plen - 1) {
-		wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
+		wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key");
 		os_free(plain);
 		return NULL;
 	}
@@ -1123,6 +1126,10 @@
 					    sent_msg->hdr->authenticator,
 					    secret, secret_len,
 					    &keys->send_len);
+		if (!keys->send) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS: Failed to decrypt send key");
+		}
 		os_free(key);
 	}
 
@@ -1134,6 +1141,10 @@
 					    sent_msg->hdr->authenticator,
 					    secret, secret_len,
 					    &keys->recv_len);
+		if (!keys->recv) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS: Failed to decrypt recv key");
+		}
 		os_free(key);
 	}
 
@@ -1414,7 +1425,7 @@
 /**
  * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
  * @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ * Returns: VLAN ID for the first tunnel configuration or 0 if none is found
  */
 int radius_msg_get_vlanid(struct radius_msg *msg)
 {
@@ -1477,7 +1488,7 @@
 			return tun->vlanid;
 	}
 
-	return -1;
+	return 0;
 }
 
 
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 1382c53..693f61e 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS client
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -236,6 +236,8 @@
 		     int sock, int sock6, int auth);
 static int radius_client_init_acct(struct radius_client_data *radius);
 static int radius_client_init_auth(struct radius_client_data *radius);
+static void radius_client_auth_failover(struct radius_client_data *radius);
+static void radius_client_acct_failover(struct radius_client_data *radius);
 
 
 static void radius_client_msg_free(struct radius_msg_list *req)
@@ -304,7 +306,7 @@
 {
 #ifndef CONFIG_NATIVE_WINDOWS
 	int _errno = errno;
-	wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
+	wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
 	    _errno == EBADF || _errno == ENETUNREACH) {
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -333,9 +335,18 @@
 	struct hostapd_radius_servers *conf = radius->conf;
 	int s;
 	struct wpabuf *buf;
+	size_t prev_num_msgs;
 
 	if (entry->msg_type == RADIUS_ACCT ||
 	    entry->msg_type == RADIUS_ACCT_INTERIM) {
+		if (radius->acct_sock < 0)
+			radius_client_init_acct(radius);
+		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
+			prev_num_msgs = radius->num_msgs;
+			radius_client_acct_failover(radius);
+			if (prev_num_msgs != radius->num_msgs)
+				return 0;
+		}
 		s = radius->acct_sock;
 		if (entry->attempts == 0)
 			conf->acct_server->requests++;
@@ -344,6 +355,14 @@
 			conf->acct_server->retransmissions++;
 		}
 	} else {
+		if (radius->auth_sock < 0)
+			radius_client_init_auth(radius);
+		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
+			prev_num_msgs = radius->num_msgs;
+			radius_client_auth_failover(radius);
+			if (prev_num_msgs != radius->num_msgs)
+				return 0;
+		}
 		s = radius->auth_sock;
 		if (entry->attempts == 0)
 			conf->auth_server->requests++;
@@ -352,6 +371,11 @@
 			conf->auth_server->retransmissions++;
 		}
 	}
+	if (s < 0) {
+		wpa_printf(MSG_INFO,
+			   "RADIUS: No valid socket for retransmission");
+		return 1;
+	}
 
 	/* retransmit; remove entry if too many attempts */
 	entry->attempts++;
@@ -388,7 +412,6 @@
 	os_time_t first;
 	struct radius_msg_list *entry, *prev, *tmp;
 	int auth_failover = 0, acct_failover = 0;
-	char abuf[50];
 	size_t prev_num_msgs;
 	int s;
 
@@ -453,54 +476,70 @@
 			       (long int) (first - now.sec));
 	}
 
-	if (auth_failover && conf->num_auth_servers > 1) {
-		struct hostapd_radius_server *next, *old;
-		old = conf->auth_server;
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "No response from Authentication server "
-			       "%s:%d - failover",
-			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
-			       old->port);
+	if (auth_failover && conf->num_auth_servers > 1)
+		radius_client_auth_failover(radius);
 
-		for (entry = radius->msgs; entry; entry = entry->next) {
-			if (entry->msg_type == RADIUS_AUTH)
-				old->timeouts++;
-		}
+	if (acct_failover && conf->num_acct_servers > 1)
+		radius_client_acct_failover(radius);
+}
 
-		next = old + 1;
-		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
-			next = conf->auth_servers;
-		conf->auth_server = next;
-		radius_change_server(radius, next, old,
-				     radius->auth_serv_sock,
-				     radius->auth_serv_sock6, 1);
+
+static void radius_client_auth_failover(struct radius_client_data *radius)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	struct hostapd_radius_server *next, *old;
+	struct radius_msg_list *entry;
+	char abuf[50];
+
+	old = conf->auth_server;
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_NOTICE,
+		       "No response from Authentication server %s:%d - failover",
+		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+		       old->port);
+
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if (entry->msg_type == RADIUS_AUTH)
+			old->timeouts++;
 	}
 
-	if (acct_failover && conf->num_acct_servers > 1) {
-		struct hostapd_radius_server *next, *old;
-		old = conf->acct_server;
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "No response from Accounting server "
-			       "%s:%d - failover",
-			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
-			       old->port);
+	next = old + 1;
+	if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
+		next = conf->auth_servers;
+	conf->auth_server = next;
+	radius_change_server(radius, next, old,
+			     radius->auth_serv_sock,
+			     radius->auth_serv_sock6, 1);
+}
 
-		for (entry = radius->msgs; entry; entry = entry->next) {
-			if (entry->msg_type == RADIUS_ACCT ||
-			    entry->msg_type == RADIUS_ACCT_INTERIM)
-				old->timeouts++;
-		}
 
-		next = old + 1;
-		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
-			next = conf->acct_servers;
-		conf->acct_server = next;
-		radius_change_server(radius, next, old,
-				     radius->acct_serv_sock,
-				     radius->acct_serv_sock6, 0);
+static void radius_client_acct_failover(struct radius_client_data *radius)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	struct hostapd_radius_server *next, *old;
+	struct radius_msg_list *entry;
+	char abuf[50];
+
+	old = conf->acct_server;
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_NOTICE,
+		       "No response from Accounting server %s:%d - failover",
+		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+		       old->port);
+
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if (entry->msg_type == RADIUS_ACCT ||
+		    entry->msg_type == RADIUS_ACCT_INTERIM)
+			old->timeouts++;
 	}
+
+	next = old + 1;
+	if (next > &conf->acct_servers[conf->num_acct_servers - 1])
+		next = conf->acct_servers;
+	conf->acct_server = next;
+	radius_change_server(radius, next, old,
+			     radius->acct_serv_sock,
+			     radius->acct_serv_sock6, 0);
 }
 
 
@@ -658,7 +697,11 @@
 	}
 
 	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
-		if (conf->acct_server == NULL || radius->acct_sock < 0) {
+		if (conf->acct_server && radius->acct_sock < 0)
+			radius_client_init_acct(radius);
+
+		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
+		    conf->acct_server->shared_secret == NULL) {
 			hostapd_logger(radius->ctx, NULL,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -672,7 +715,11 @@
 		s = radius->acct_sock;
 		conf->acct_server->requests++;
 	} else {
-		if (conf->auth_server == NULL || radius->auth_sock < 0) {
+		if (conf->auth_server && radius->auth_sock < 0)
+			radius_client_init_auth(radius);
+
+		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
+		    conf->auth_server->shared_secret == NULL) {
 			hostapd_logger(radius->ctx, NULL,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -1129,18 +1176,28 @@
 	    conf->auth_server != conf->auth_servers) {
 		oserv = conf->auth_server;
 		conf->auth_server = conf->auth_servers;
-		radius_change_server(radius, conf->auth_server, oserv,
-				     radius->auth_serv_sock,
-				     radius->auth_serv_sock6, 1);
+		if (radius_change_server(radius, conf->auth_server, oserv,
+					 radius->auth_serv_sock,
+					 radius->auth_serv_sock6, 1) < 0) {
+			conf->auth_server = oserv;
+			radius_change_server(radius, oserv, conf->auth_server,
+					     radius->auth_serv_sock,
+					     radius->auth_serv_sock6, 1);
+		}
 	}
 
 	if (radius->acct_sock >= 0 && conf->acct_servers &&
 	    conf->acct_server != conf->acct_servers) {
 		oserv = conf->acct_server;
 		conf->acct_server = conf->acct_servers;
-		radius_change_server(radius, conf->acct_server, oserv,
-				     radius->acct_serv_sock,
-				     radius->acct_serv_sock6, 0);
+		if (radius_change_server(radius, conf->acct_server, oserv,
+					 radius->acct_serv_sock,
+					 radius->acct_serv_sock6, 0) < 0) {
+			conf->acct_server = oserv;
+			radius_change_server(radius, oserv, conf->acct_server,
+					     radius->acct_serv_sock,
+					     radius->acct_serv_sock6, 0);
+		}
 	}
 
 	if (conf->retry_primary_interval)
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index 9655f4c..39ceea8 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -42,6 +42,7 @@
 		RADIUS_ATTR_CALLING_STATION_ID,
 		RADIUS_ATTR_NAS_IDENTIFIER,
 		RADIUS_ATTR_ACCT_SESSION_ID,
+		RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
 		RADIUS_ATTR_EVENT_TIMESTAMP,
 		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
 		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -129,6 +130,12 @@
 		attrs.acct_session_id_len = len;
 	}
 
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+				    &buf, &len, NULL) == 0) {
+		attrs.acct_multi_session_id = buf;
+		attrs.acct_multi_session_id_len = len;
+	}
+
 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
 				    &buf, &len, NULL) == 0) {
 		attrs.cui = buf;
@@ -147,6 +154,12 @@
 			   "%s:%d", abuf, from_port);
 		error = 503;
 		break;
+	case RADIUS_DAS_MULTI_SESSION_MATCH:
+		wpa_printf(MSG_INFO,
+			   "DAS: Multiple sessions match for request from %s:%d",
+			   abuf, from_port);
+		error = 508;
+		break;
 	case RADIUS_DAS_SUCCESS:
 		error = 0;
 		break;
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index e3ed540..ce731d4 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -14,7 +14,8 @@
 enum radius_das_res {
 	RADIUS_DAS_SUCCESS,
 	RADIUS_DAS_NAS_MISMATCH,
-	RADIUS_DAS_SESSION_NOT_FOUND
+	RADIUS_DAS_SESSION_NOT_FOUND,
+	RADIUS_DAS_MULTI_SESSION_MATCH,
 };
 
 struct radius_das_attrs {
@@ -30,6 +31,8 @@
 	size_t user_name_len;
 	const u8 *acct_session_id;
 	size_t acct_session_id_len;
+	const u8 *acct_multi_session_id;
+	size_t acct_multi_session_id_len;
 	const u8 *cui;
 	size_t cui_len;
 };
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 85a485e..3f881cf 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -2035,6 +2035,12 @@
 		sess->remediation = user->remediation;
 		sess->macacl = user->macacl;
 	}
+
+	if (ret) {
+		RADIUS_DEBUG("%s: User-Name not found from user database",
+			     __func__);
+	}
+
 	return ret;
 }
 
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index adfd3df..d5e61fe 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -1,8 +1,30 @@
-all:
-	@echo Nothing to be made.
+all: librsn_supp.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov librsn_supp.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_PEERKEY
+CFLAGS += -DCONFIG_TDLS
+CFLAGS += -DCONFIG_WNM
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS= \
+	pmksa_cache.o \
+	wpa_ft.o \
+	peerkey.o \
+	tdls.o \
+	preauth.o \
+	wpa.o \
+	wpa_ie.o
+
+librsn_supp.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index aca8f54..79764d9 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -65,6 +65,7 @@
 {
 	size_t rlen;
 	struct wpa_eapol_key *err;
+	struct wpa_eapol_key_192 *err192;
 	struct rsn_error_kde error;
 	u8 *rbuf, *pos;
 	size_t kde_len;
@@ -79,6 +80,7 @@
 				  (void *) &err);
 	if (rbuf == NULL)
 		return -1;
+	err192 = (struct wpa_eapol_key_192 *) err;
 
 	err->type = EAPOL_KEY_TYPE_RSN;
 	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -112,8 +114,8 @@
 			   "(mui %d error_type %d)", mui, error_type);
 	}
 
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, err->key_mic);
+	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+			   ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
 
 	return 0;
 }
@@ -126,6 +128,7 @@
 {
 	size_t rlen;
 	struct wpa_eapol_key *reply;
+	struct wpa_eapol_key_192 *reply192;
 	u8 *rbuf, *pos;
 	size_t kde_len;
 	u16 key_info;
@@ -140,6 +143,7 @@
 				  (void *) &reply);
 	if (rbuf == NULL)
 		return -1;
+	reply192 = (struct wpa_eapol_key_192 *) reply;
 
 	reply->type = EAPOL_KEY_TYPE_RSN;
 	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -164,8 +168,8 @@
 	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
 
 	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
+	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
+			   ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
 
 	return 0;
 }
@@ -240,12 +244,7 @@
 	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
 	peerkey->rsnie_i_len = kde.rsn_ie_len;
 	peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
-	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			   WPA_KEY_MGMT_PSK_SHA256 |
-			   WPA_KEY_MGMT_IEEE8021X_SUITE_B))
-		peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+	peerkey->akmp = ie.key_mgmt;
 
 	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -289,14 +288,14 @@
  * @mac_p: Peer MAC address
  * @inonce: Initiator Nonce
  * @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
  *
  * 8.5.1.4 Station to station (STK) key hierarchy
  * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
  */
 static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
 		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
-		      int use_sha256)
+		      int akmp)
 {
 	char *title = "SMK Name";
 	const u8 *addr[5];
@@ -311,7 +310,7 @@
 	addr[4] = mac_i;
 
 #ifdef CONFIG_IEEE80211W
-	if (use_sha256)
+	if (wpa_key_mgmt_sha256(akmp))
 		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
 	else
 #endif /* CONFIG_IEEE80211W */
@@ -372,7 +371,7 @@
 
 	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
 		   MAC2STR(peerkey->addr));
-	wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+	wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
 			   mbuf, mlen, NULL);
 }
 
@@ -427,8 +426,9 @@
 
 	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
 		   MAC2STR(peerkey->addr));
-	wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
-			   ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+	wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+			   peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+			   msg->key_mic);
 }
 
 
@@ -576,12 +576,12 @@
 	if (peerkey->initiator) {
 		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
 			  peerkey->inonce, sm->own_addr, peerkey->smkid,
-			  peerkey->use_sha256);
+			  peerkey->akmp);
 		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
 	} else {
 		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
 			  peerkey->inonce, peerkey->addr, peerkey->smkid,
-			  peerkey->use_sha256);
+			  peerkey->akmp);
 	}
 	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
 
@@ -695,12 +695,11 @@
 	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 		       sm->own_addr, peerkey->addr,
 		       peerkey->pnonce, key->key_nonce,
-		       (u8 *) stk, sizeof(*stk),
-		       peerkey->use_sha256);
+		       stk, peerkey->akmp, peerkey->cipher);
 	/* Supplicant: swap tx/rx Mic keys */
-	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
-	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
-	os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+	os_memcpy(buf, &stk->tk[16], 8);
+	os_memcpy(&stk->tk[16], &stk->tk[24], 8);
+	os_memcpy(&stk->tk[24], buf, 8);
 	peerkey->tstk_set = 1;
 
 	kde_buf_len = peerkey->rsnie_p_len +
@@ -856,12 +855,12 @@
 				       &peerkey->stk))
 		return;
 
-	_key = (u8 *) peerkey->stk.tk1;
+	_key = peerkey->stk.tk;
 	if (peerkey->cipher == WPA_CIPHER_TKIP) {
 		/* Swap Tx/Rx keys for Michael MIC */
 		os_memcpy(key_buf, _key, 16);
-		os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
-		os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+		os_memcpy(key_buf + 16, _key + 24, 8);
+		os_memcpy(key_buf + 24, _key + 16, 8);
 		_key = key_buf;
 		key_len = 32;
 	} else
@@ -870,10 +869,12 @@
 	os_memset(rsc, 0, 6);
 	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
 			   rsc, sizeof(rsc), _key, key_len) < 0) {
+		os_memset(key_buf, 0, sizeof(key_buf));
 		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
 			   "driver.");
 		return;
 	}
+	os_memset(key_buf, 0, sizeof(key_buf));
 }
 
 
@@ -889,7 +890,7 @@
 
 	os_memset(rsc, 0, 6);
 	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
-			   rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+			   rsc, sizeof(rsc), peerkey->stk.tk,
 			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
 		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
 			   "driver.");
@@ -910,27 +911,27 @@
  */
 int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
 				 struct wpa_peerkey *peerkey,
-				 struct wpa_eapol_key *key, u16 ver,
+				 struct wpa_eapol_key_192 *key, u16 ver,
 				 const u8 *buf, size_t len)
 {
-	u8 mic[16];
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+	size_t mic_len = 16;
 	int ok = 0;
 
 	if (peerkey->initiator && !peerkey->stk_set) {
 		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 			       sm->own_addr, peerkey->addr,
 			       peerkey->inonce, key->key_nonce,
-			       (u8 *) &peerkey->stk, sizeof(peerkey->stk),
-			       peerkey->use_sha256);
+			       &peerkey->stk, peerkey->akmp, peerkey->cipher);
 		peerkey->stk_set = 1;
 	}
 
-	os_memcpy(mic, key->key_mic, 16);
+	os_memcpy(mic, key->key_mic, mic_len);
 	if (peerkey->tstk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->tstk.kck, sm->key_mgmt, ver, buf,
-				  len, key->key_mic);
-		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+		os_memset(key->key_mic, 0, mic_len);
+		wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
+				  sm->key_mgmt, ver, buf, len, key->key_mic);
+		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
 			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
 				   "when using TSTK - ignoring TSTK");
 		} else {
@@ -939,14 +940,15 @@
 			peerkey->stk_set = 1;
 			os_memcpy(&peerkey->stk, &peerkey->tstk,
 				  sizeof(peerkey->stk));
+			os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
 		}
 	}
 
 	if (!ok && peerkey->stk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->stk.kck, sm->key_mgmt, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+		os_memset(key->key_mic, 0, mic_len);
+		wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
+				  sm->key_mgmt, ver, buf, len, key->key_mic);
+		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
 			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
 				   "- dropping packet");
 			return -1;
@@ -1015,10 +1017,7 @@
 		return -1;
 	peerkey->initiator = 1;
 	os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
-	if (wpa_key_mgmt_sha256(sm->key_mgmt))
-		peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+	peerkey->akmp = sm->key_mgmt;
 
 	/* SMK M1:
 	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
@@ -1085,8 +1084,8 @@
 
 	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
 		   MACSTR ")", MAC2STR(peer));
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
-			   rbuf, rlen, req->key_mic);
+	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+			   ETH_P_EAPOL, rbuf, rlen, req->key_mic);
 
 	peerkey->next = sm->peerkey;
 	sm->peerkey = peerkey;
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index 4c17eae..6ccd948 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,7 +27,7 @@
 	int cipher; /* Selected cipher (WPA_CIPHER_*) */
 	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int replay_counter_set;
-	int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+	int akmp;
 
 	struct wpa_ptk stk, tstk;
 	int stk_set, tstk_set;
@@ -38,7 +38,7 @@
 
 int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
 				 struct wpa_peerkey *peerkey,
-				 struct wpa_eapol_key *key, u16 ver,
+				 struct wpa_eapol_key_192 *key, u16 ver,
 				 const u8 *buf, size_t len);
 void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
 			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 8af04d0..ef7b683 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -141,7 +141,9 @@
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
-	if (wpa_key_mgmt_suite_b(akmp))
+	if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+	else if (wpa_key_mgmt_suite_b(akmp))
 		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
 	else
 		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index af0e108..c6534af 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -1,6 +1,6 @@
 /*
  * RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -172,6 +172,7 @@
 {
 	struct eapol_config eapol_conf;
 	struct eapol_ctx *ctx;
+	int ret;
 
 	if (sm->preauth_eapol)
 		return -1;
@@ -197,14 +198,16 @@
 			wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
 				   "packet processing (bridge) for "
 				   "pre-authentication");
-			return -2;
+			ret = -2;
+			goto fail;
 		}
 	}
 
 	ctx = os_zalloc(sizeof(*ctx));
 	if (ctx == NULL) {
 		wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
-		return -4;
+		ret = -4;
+		goto fail;
 	}
 	ctx->ctx = sm->ctx->ctx;
 	ctx->msg_ctx = sm->ctx->ctx;
@@ -222,7 +225,8 @@
 		os_free(ctx);
 		wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
 			   "state machines for pre-authentication");
-		return -3;
+		ret = -3;
+		goto fail;
 	}
 	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
 	eapol_conf.accept_802_1x_keys = 0;
@@ -247,6 +251,15 @@
 			       rsn_preauth_timeout, sm, NULL);
 
 	return 0;
+
+fail:
+	if (sm->l2_preauth_br) {
+		l2_packet_deinit(sm->l2_preauth_br);
+		sm->l2_preauth_br = NULL;
+	}
+	l2_packet_deinit(sm->l2_preauth);
+	sm->l2_preauth = NULL;
+	return ret;
 }
 
 
@@ -300,7 +313,8 @@
 	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
 	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
 	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B)) {
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
 			"state for new pre-authentication");
 		return; /* invalid state for new pre-auth */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8cb19a2..6b1df71 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -148,6 +148,9 @@
 	size_t supp_oper_classes_len;
 
 	u8 wmm_capable;
+
+	/* channel switch currently enabled */
+	int chan_switch_enabled;
 };
 
 
@@ -687,6 +690,7 @@
 	peer->qos_info = 0;
 	peer->wmm_capable = 0;
 	peer->tpk_set = peer->tpk_success = 0;
+	peer->chan_switch_enabled = 0;
 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
 	os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
@@ -742,6 +746,13 @@
 		return 0;
 	}
 
+	/* Cancel active channel switch before teardown */
+	if (peer->chan_switch_enabled) {
+		wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+			   " to base channel", MAC2STR(addr));
+		wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+	}
+
 	dialog_token = peer->dtoken;
 
 	wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -858,9 +869,11 @@
 
 	if (wpa_tdls_is_external_setup(sm)) {
 		/*
-		 * Disable the link, send a teardown packet through the
-		 * AP, and then reset link data.
+		 * Get us on the base channel, disable the link, send a
+		 * teardown packet through the AP, and then reset link data.
 		 */
+		if (peer->chan_switch_enabled)
+			wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
 		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
 		wpa_tdls_send_teardown(sm, addr,
 				       WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
@@ -926,10 +939,15 @@
 		   " (reason code %u)", MAC2STR(src_addr), reason_code);
 
 	ielen = len - (pos - buf); /* start of IE in buf */
-	if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
-		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown");
-		return -1;
-	}
+
+	/*
+	 * Don't reject the message if failing to parse IEs. The IEs we need are
+	 * explicitly checked below. Some APs may add arbitrary padding to the
+	 * end of short TDLS frames and that would look like invalid IEs.
+	 */
+	if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0)
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround");
 
 	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
 		wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
@@ -1559,9 +1577,7 @@
 static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
 			      struct wpa_tdls_peer *peer)
 {
-	if (!kde->ht_capabilities ||
-	    kde->ht_capabilities_len <
-	    sizeof(struct ieee80211_ht_capabilities) ) {
+	if (!kde->ht_capabilities) {
 		wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
 			   "received");
 		return 0;
@@ -1587,9 +1603,7 @@
 static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
 			      struct wpa_tdls_peer *peer)
 {
-	if (!kde->vht_capabilities ||
-	    kde->vht_capabilities_len <
-	    sizeof(struct ieee80211_vht_capabilities) ) {
+	if (!kde->vht_capabilities) {
 		wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities "
 			   "received");
 		return 0;
@@ -1810,10 +1824,15 @@
 	cpos += 2;
 
 	ielen = len - (cpos - buf); /* start of IE in buf */
-	if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
-		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1");
-		goto error;
-	}
+
+	/*
+	 * Don't reject the message if failing to parse IEs. The IEs we need are
+	 * explicitly checked below. Some APs may add arbitrary padding to the
+	 * end of short TDLS frames and that would look like invalid IEs.
+	 */
+	if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0)
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround");
 
 	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
 		wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
@@ -2186,10 +2205,15 @@
 	pos += 2;
 
 	ielen = len - (pos - buf); /* start of IE in buf */
-	if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
-		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
-		goto error;
-	}
+
+	/*
+	 * Don't reject the message if failing to parse IEs. The IEs we need are
+	 * explicitly checked below. Some APs may add arbitrary padding to the
+	 * end of short TDLS frames and that would look like invalid IEs.
+	 */
+	if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0)
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround");
 
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_DECLINE_RESP) {
@@ -2742,7 +2766,8 @@
 	 * are assumed to perform everything internally
 	 */
 	if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
-				 &sm->tdls_external_setup) < 0) {
+				 &sm->tdls_external_setup,
+				 &sm->tdls_chan_switch) < 0) {
 		sm->tdls_supported = 1;
 		sm->tdls_external_setup = 0;
 	}
@@ -2751,6 +2776,8 @@
 		   "driver", sm->tdls_supported ? "" : " not");
 	wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
 		   sm->tdls_external_setup ? "external" : "internal");
+	wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching",
+		   sm->tdls_chan_switch ? "supports" : "does not support");
 
 	return 0;
 }
@@ -2760,6 +2787,8 @@
 {
 	struct wpa_tdls_peer *peer, *tmp;
 
+	if (!sm)
+		return;
 	peer = sm->tdls;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
@@ -2830,39 +2859,61 @@
 }
 
 
-static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems)
 {
-	struct wpa_eapol_ie_parse elems;
+	/* bit 38 - TDLS Prohibited */
+	return !!(elems->ext_capab[2 + 4] & 0x40);
+}
 
-	if (ies == NULL)
-		return 0;
 
-	if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
-		return 0;
-
-	if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
-		return 0;
-
-	 /* bit 38 - TDLS Prohibited */
-	return !!(elems.ext_capab[2 + 4] & 0x40);
+static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems)
+{
+	/* bit 39 - TDLS Channel Switch Prohibited */
+	return !!(elems->ext_capab[2 + 4] & 0x80);
 }
 
 
 void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
 {
-	sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+	struct wpa_eapol_ie_parse elems;
+
+	sm->tdls_prohibited = 0;
+	sm->tdls_chan_switch_prohibited = 0;
+
+	if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+	    elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+		return;
+
+	sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
 	wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
 		   sm->tdls_prohibited ? "prohibited" : "allowed");
+	sm->tdls_chan_switch_prohibited =
+		wpa_tdls_chan_switch_prohibited(&elems);
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS",
+		   sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed");
 }
 
 
 void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
 {
-	if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+	struct wpa_eapol_ie_parse elems;
+
+	if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+	    elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+		return;
+
+	if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
 		wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
 			   "(Re)Association Response IEs");
 		sm->tdls_prohibited = 1;
 	}
+
+	if (!sm->tdls_chan_switch_prohibited &&
+	    wpa_tdls_chan_switch_prohibited(&elems)) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs");
+		sm->tdls_chan_switch_prohibited = 1;
+	}
 }
 
 
@@ -2877,3 +2928,78 @@
 {
 	return sm->tdls_external_setup;
 }
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+				u8 oper_class,
+				struct hostapd_freq_params *freq_params)
+{
+	struct wpa_tdls_peer *peer;
+	int ret;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	if (!sm->tdls_chan_switch) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Channel switching not supported by the driver");
+		return -1;
+	}
+
+	if (sm->tdls_chan_switch_prohibited) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+		return -1;
+	}
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL || !peer->tpk_success) {
+		wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+			   " not found for channel switching", MAC2STR(addr));
+		return -1;
+	}
+
+	if (peer->chan_switch_enabled) {
+		wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+			   " already has channel switching enabled",
+			   MAC2STR(addr));
+		return 0;
+	}
+
+	ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+						oper_class, freq_params);
+	if (!ret)
+		peer->chan_switch_enabled = 1;
+
+	return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (!peer || !peer->chan_switch_enabled) {
+		wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+			   MACSTR, MAC2STR(addr));
+		return -1;
+	}
+
+	/* ignore the return value */
+	wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+	peer->chan_switch_enabled = 0;
+	return 0;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 8ea54bb..8adeef4 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,7 @@
  * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @kck: Key Confirmation Key (KCK, part of PTK)
+ * @kck_len: KCK length in octets
  * @ver: Version field from Key Info
  * @dest: Destination address for the frame
  * @proto: Ethertype (usually ETH_P_EAPOL)
@@ -34,10 +35,12 @@
  * @msg_len: Length of message
  * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
  */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
 			int ver, const u8 *dest, u16 proto,
 			u8 *msg, size_t msg_len, u8 *key_mic)
 {
+	size_t mic_len = wpa_mic_len(sm->key_mgmt);
+
 	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
 		/*
 		 * Association event was not yet received; try to fetch
@@ -56,14 +59,15 @@
 		}
 	}
 	if (key_mic &&
-	    wpa_eapol_key_mic(kck, sm->key_mgmt, ver, msg, msg_len, key_mic)) {
+	    wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
+			      key_mic)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
 			"WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
 			ver, sm->key_mgmt);
 		goto out;
 	}
-	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
-	wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
+	wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
 	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
 	wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
 	eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -84,10 +88,11 @@
  */
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 {
-	size_t rlen;
+	size_t mic_len, hdrlen, rlen;
 	struct wpa_eapol_key *reply;
+	struct wpa_eapol_key_192 *reply192;
 	int key_info, ver;
-	u8 bssid[ETH_ALEN], *rbuf;
+	u8 bssid[ETH_ALEN], *rbuf, *key_mic;
 
 	if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
 	    wpa_key_mgmt_suite_b(sm->key_mgmt))
@@ -106,10 +111,13 @@
 		return;
 	}
 
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply), &rlen, (void *) &reply);
+				  hdrlen, &rlen, (void *) &reply);
 	if (rbuf == NULL)
 		return;
+	reply192 = (struct wpa_eapol_key_192 *) reply;
 
 	reply->type = (sm->proto == WPA_PROTO_RSN ||
 		       sm->proto == WPA_PROTO_OSEN) ?
@@ -127,15 +135,21 @@
 		  WPA_REPLAY_COUNTER_LEN);
 	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
 
-	WPA_PUT_BE16(reply->key_data_length, 0);
+	if (mic_len == 24)
+		WPA_PUT_BE16(reply192->key_data_length, 0);
+	else
+		WPA_PUT_BE16(reply->key_data_length, 0);
+	if (!(key_info & WPA_KEY_INFO_MIC))
+		key_mic = NULL;
+	else
+		key_mic = reply192->key_mic; /* same offset in reply */
 
 	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 		"WPA: Sending EAPOL-Key Request (error=%d "
 		"pairwise=%d ptk_set=%d len=%lu)",
 		error, pairwise, sm->ptk_set, (unsigned long) rlen);
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
-			   rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
-			   reply->key_mic : NULL);
+	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+			   ETH_P_EAPOL, rbuf, rlen, key_mic);
 }
 
 
@@ -301,9 +315,10 @@
 			       const u8 *wpa_ie, size_t wpa_ie_len,
 			       struct wpa_ptk *ptk)
 {
-	size_t rlen;
+	size_t mic_len, hdrlen, rlen;
 	struct wpa_eapol_key *reply;
-	u8 *rbuf;
+	struct wpa_eapol_key_192 *reply192;
+	u8 *rbuf, *key_mic;
 	u8 *rsn_ie_buf = NULL;
 
 	if (wpa_ie == NULL) {
@@ -345,13 +360,16 @@
 
 	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
 
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
-				  NULL, sizeof(*reply) + wpa_ie_len,
+				  NULL, hdrlen + wpa_ie_len,
 				  &rlen, (void *) &reply);
 	if (rbuf == NULL) {
 		os_free(rsn_ie_buf);
 		return -1;
 	}
+	reply192 = (struct wpa_eapol_key_192 *) reply;
 
 	reply->type = (sm->proto == WPA_PROTO_RSN ||
 		       sm->proto == WPA_PROTO_OSEN) ?
@@ -367,35 +385,38 @@
 	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
 		    WPA_REPLAY_COUNTER_LEN);
 
-	WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
-	os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+	key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+	if (mic_len == 24) {
+		WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
+		os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
+	} else {
+		WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+		os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+	}
 	os_free(rsn_ie_buf);
 
 	os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
-	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
+	wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, key_mic);
 
 	return 0;
 }
 
 
 static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
-			  const struct wpa_eapol_key *key,
-			  struct wpa_ptk *ptk)
+			  const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
 {
-	size_t ptk_len = wpa_cipher_key_len(sm->pairwise_cipher) + 32;
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt))
-		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+		return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
 #endif /* CONFIG_IEEE80211R */
 
-	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
-		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
-		       (u8 *) ptk, ptk_len,
-		       wpa_key_mgmt_sha256(sm->key_mgmt));
-	return 0;
+	return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+			      sm->own_addr, sm->bssid, sm->snonce,
+			      key->key_nonce, ptk, sm->key_mgmt,
+			      sm->pairwise_cipher);
 }
 
 
@@ -462,9 +483,9 @@
 	if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
 		u8 buf[8];
 		/* Supplicant: swap tx/rx Mic keys */
-		os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
-		os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
-		os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+		os_memcpy(buf, &ptk->tk[16], 8);
+		os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
+		os_memcpy(&ptk->tk[24], buf, 8);
 		os_memset(buf, 0, sizeof(buf));
 	}
 	sm->tptk_set = 1;
@@ -601,7 +622,7 @@
 	}
 
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   (u8 *) sm->ptk.tk1, keylen) < 0) {
+			   sm->ptk.tk, keylen) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set PTK to the "
 			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -610,8 +631,7 @@
 	}
 
 	/* TK is not needed anymore in supplicant */
-	os_memset(sm->ptk.tk1, 0, sizeof(sm->ptk.tk1));
-	os_memset(sm->ptk.u.tk2, 0, sizeof(sm->ptk.u.tk2));
+	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
 
 	if (sm->wpa_ptk_rekey) {
 		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -1062,14 +1082,18 @@
 			       u16 ver, u16 key_info,
 			       struct wpa_ptk *ptk)
 {
-	size_t rlen;
+	size_t mic_len, hdrlen, rlen;
 	struct wpa_eapol_key *reply;
-	u8 *rbuf;
+	struct wpa_eapol_key_192 *reply192;
+	u8 *rbuf, *key_mic;
 
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply), &rlen, (void *) &reply);
+				  hdrlen, &rlen, (void *) &reply);
 	if (rbuf == NULL)
 		return -1;
+	reply192 = (struct wpa_eapol_key_192 *) reply;
 
 	reply->type = (sm->proto == WPA_PROTO_RSN ||
 		       sm->proto == WPA_PROTO_OSEN) ?
@@ -1084,11 +1108,15 @@
 	os_memcpy(reply->replay_counter, key->replay_counter,
 		  WPA_REPLAY_COUNTER_LEN);
 
-	WPA_PUT_BE16(reply->key_data_length, 0);
+	key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+	if (mic_len == 24)
+		WPA_PUT_BE16(reply192->key_data_length, 0);
+	else
+		WPA_PUT_BE16(reply->key_data_length, 0);
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
-	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
+	wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, key_mic);
 
 	return 0;
 }
@@ -1209,13 +1237,14 @@
 		struct rsn_pmksa_cache_entry *sa;
 
 		sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
-				     sm->ptk.kck, sizeof(sm->ptk.kck),
+				     sm->ptk.kck, sm->ptk.kck_len,
 				     sm->bssid, sm->own_addr,
 				     sm->network_ctx, sm->key_mgmt);
 		if (!sm->cur_pmksa)
 			sm->cur_pmksa = sa;
 	}
 
+	sm->msg_3_of_4_ok = 1;
 	return;
 
 failed:
@@ -1303,7 +1332,7 @@
 	gd->gtk_len = gtk_len;
 	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
 		WPA_KEY_INFO_KEY_INDEX_SHIFT;
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
 		u8 ek[32];
 		if (key_data_len > sizeof(gd->gtk)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1312,7 +1341,7 @@
 			return -1;
 		}
 		os_memcpy(ek, key->key_iv, 16);
-		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
 		os_memcpy(gd->gtk, key_data, key_data_len);
 		if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
 			os_memset(ek, 0, sizeof(ek));
@@ -1336,8 +1365,8 @@
 				(unsigned long) maxkeylen);
 			return -1;
 		}
-		if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data,
-			       gd->gtk)) {
+		if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8,
+			       key_data, gd->gtk)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: AES unwrap failed - could not decrypt "
 				"GTK");
@@ -1358,14 +1387,18 @@
 				      const struct wpa_eapol_key *key,
 				      int ver, u16 key_info)
 {
-	size_t rlen;
+	size_t mic_len, hdrlen, rlen;
 	struct wpa_eapol_key *reply;
-	u8 *rbuf;
+	struct wpa_eapol_key_192 *reply192;
+	u8 *rbuf, *key_mic;
 
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply), &rlen, (void *) &reply);
+				  hdrlen, &rlen, (void *) &reply);
 	if (rbuf == NULL)
 		return -1;
+	reply192 = (struct wpa_eapol_key_192 *) reply;
 
 	reply->type = (sm->proto == WPA_PROTO_RSN ||
 		       sm->proto == WPA_PROTO_OSEN) ?
@@ -1380,11 +1413,15 @@
 	os_memcpy(reply->replay_counter, key->replay_counter,
 		  WPA_REPLAY_COUNTER_LEN);
 
-	WPA_PUT_BE16(reply->key_data_length, 0);
+	key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+	if (mic_len == 24)
+		WPA_PUT_BE16(reply192->key_data_length, 0);
+	else
+		WPA_PUT_BE16(reply->key_data_length, 0);
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
+	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
+			   ETH_P_EAPOL, rbuf, rlen, key_mic);
 
 	return 0;
 }
@@ -1400,6 +1437,12 @@
 	int rekey, ret;
 	struct wpa_gtk_data gd;
 
+	if (!sm->msg_3_of_4_ok) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Group Key Handshake started prior to completion of 4-way handshake");
+		goto failed;
+	}
+
 	os_memset(&gd, 0, sizeof(gd));
 
 	rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
@@ -1451,19 +1494,20 @@
 
 
 static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
-					       struct wpa_eapol_key *key,
+					       struct wpa_eapol_key_192 *key,
 					       u16 ver,
 					       const u8 *buf, size_t len)
 {
-	u8 mic[16];
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
 	int ok = 0;
+	size_t mic_len = wpa_mic_len(sm->key_mgmt);
 
-	os_memcpy(mic, key->key_mic, 16);
+	os_memcpy(mic, key->key_mic, mic_len);
 	if (sm->tptk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->tptk.kck, sm->key_mgmt, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+		os_memset(key->key_mic, 0, mic_len);
+		wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
+				  ver, buf, len, key->key_mic);
+		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Invalid EAPOL-Key MIC "
 				"when using TPTK - ignoring TPTK");
@@ -1477,10 +1521,10 @@
 	}
 
 	if (!ok && sm->ptk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->ptk.kck, sm->key_mgmt, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+		os_memset(key->key_mic, 0, mic_len);
+		wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
+				  ver, buf, len, key->key_mic);
+		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Invalid EAPOL-Key MIC - "
 				"dropping packet");
@@ -1519,10 +1563,10 @@
 
 	/* Decrypt key data here so that this operation does not need
 	 * to be implemented separately for each message type. */
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
 		u8 ek[32];
 		os_memcpy(ek, key->key_iv, 16);
-		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
 		if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
 			os_memset(ek, 0, sizeof(ek));
 			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
@@ -1548,7 +1592,7 @@
 				"WPA: No memory for AES-UNWRAP buffer");
 			return -1;
 		}
-		if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8,
+		if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
 			       key_data, buf)) {
 			os_free(buf);
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1585,7 +1629,9 @@
 
 
 static void wpa_eapol_key_dump(struct wpa_sm *sm,
-			       const struct wpa_eapol_key *key)
+			       const struct wpa_eapol_key *key,
+			       unsigned int key_data_len,
+			       const u8 *mic, unsigned int mic_len)
 {
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	u16 key_info = WPA_GET_BE16(key->key_info);
@@ -1607,15 +1653,14 @@
 		key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 		"  key_length=%u key_data_length=%u",
-		WPA_GET_BE16(key->key_length),
-		WPA_GET_BE16(key->key_data_length));
+		WPA_GET_BE16(key->key_length), key_data_len);
 	wpa_hexdump(MSG_DEBUG, "  replay_counter",
 		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
 	wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
 	wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16);
 	wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8);
 	wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8);
-	wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16);
+	wpa_hexdump(MSG_DEBUG, "  key_mic", mic, mic_len);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 }
 
@@ -1642,22 +1687,27 @@
 	size_t plen, data_len, key_data_len;
 	const struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
+	struct wpa_eapol_key_192 *key192;
 	u16 key_info, ver;
 	u8 *tmp = NULL;
 	int ret = -1;
 	struct wpa_peerkey *peerkey = NULL;
 	u8 *key_data;
+	size_t mic_len, keyhdrlen;
 
 #ifdef CONFIG_IEEE80211R
 	sm->ft_completed = 0;
 #endif /* CONFIG_IEEE80211R */
 
-	if (len < sizeof(*hdr) + sizeof(*key)) {
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+	if (len < sizeof(*hdr) + keyhdrlen) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 			"WPA: EAPOL frame too short to be a WPA "
 			"EAPOL-Key (len %lu, expecting at least %lu)",
 			(unsigned long) len,
-			(unsigned long) sizeof(*hdr) + sizeof(*key));
+			(unsigned long) sizeof(*hdr) + keyhdrlen);
 		return 0;
 	}
 
@@ -1679,7 +1729,7 @@
 		goto out;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
-	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+	if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 			"WPA: EAPOL frame payload size %lu "
 			"invalid (frame size %lu)",
@@ -1702,7 +1752,12 @@
 		goto out;
 	os_memcpy(tmp, buf, data_len);
 	key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
-	key_data = (u8 *) (key + 1);
+	key192 = (struct wpa_eapol_key_192 *)
+		(tmp + sizeof(struct ieee802_1x_hdr));
+	if (mic_len == 24)
+		key_data = (u8 *) (key192 + 1);
+	else
+		key_data = (u8 *) (key + 1);
 
 	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
 	{
@@ -1712,14 +1767,18 @@
 		ret = 0;
 		goto out;
 	}
-	wpa_eapol_key_dump(sm, key);
 
-	key_data_len = WPA_GET_BE16(key->key_data_length);
-	if (key_data_len > plen - sizeof(struct wpa_eapol_key)) {
+	if (mic_len == 24)
+		key_data_len = WPA_GET_BE16(key192->key_data_length);
+	else
+		key_data_len = WPA_GET_BE16(key->key_data_length);
+	wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+
+	if (key_data_len > plen - keyhdrlen) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
 			"frame - key_data overflow (%u > %u)",
 			(unsigned int) key_data_len,
-			(unsigned int) (plen - sizeof(struct wpa_eapol_key)));
+			(unsigned int) (plen - keyhdrlen));
 		goto out;
 	}
 
@@ -1869,12 +1928,13 @@
 	}
 
 	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
-	    wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+	    wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
 		goto out;
 
 #ifdef CONFIG_PEERKEY
 	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
-	    peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+	    peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+					 data_len))
 		goto out;
 #endif /* CONFIG_PEERKEY */
 
@@ -1964,6 +2024,8 @@
 		return WPA_AUTH_KEY_MGMT_NONE;
 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
 		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
 	default:
 		return 0;
 	}
@@ -2227,6 +2289,8 @@
  */
 void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 {
+	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
 	peerkey_deinit(sm);
 	rsn_preauth_deinit(sm);
 	pmksa_cache_clear_current(sm);
@@ -2238,6 +2302,8 @@
 
 	/* Keys are not needed in the WPA state machine anymore */
 	wpa_sm_drop_sa(sm);
+
+	sm->msg_3_of_4_ok = 0;
 }
 
 
@@ -2870,15 +2936,18 @@
 }
 
 
-void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
-			    const u8 *ptk_kek)
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+			    const u8 *ptk_kck, size_t ptk_kck_len,
+			    const u8 *ptk_kek, size_t ptk_kek_len)
 {
-	if (ptk_kck) {
-		os_memcpy(sm->ptk.kck, ptk_kck, 16);
+	if (ptk_kck && ptk_kck_len <= WPA_KCK_MAX_LEN) {
+		os_memcpy(sm->ptk.kck, ptk_kck, ptk_kck_len);
+		sm->ptk.kck_len = ptk_kck_len;
 		wpa_printf(MSG_DEBUG, "Updated PTK KCK");
 	}
-	if (ptk_kek) {
-		os_memcpy(sm->ptk.kek, ptk_kek, 16);
+	if (ptk_kek && ptk_kek_len <= WPA_KEK_MAX_LEN) {
+		os_memcpy(sm->ptk.kek, ptk_kek, ptk_kek_len);
+		sm->ptk.kek_len = ptk_kek_len;
 		wpa_printf(MSG_DEBUG, "Updated PTK KEK");
 	}
 	sm->ptk_set = 1;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 355ed13..e163b70 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -17,6 +17,7 @@
 struct wpa_sm;
 struct eapol_sm;
 struct wpa_config_blob;
+struct hostapd_freq_params;
 
 struct wpa_sm_ctx {
 	void *ctx; /* pointer to arbitrary upper level context */
@@ -51,7 +52,7 @@
 	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
 #ifdef CONFIG_TDLS
 	int (*tdls_get_capa)(void *ctx, int *tdls_supported,
-			     int *tdls_ext_setup);
+			     int *tdls_ext_setup, int *tdls_chan_switch);
 	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, u32 peer_capab,
@@ -67,8 +68,13 @@
 				size_t supp_channels_len,
 				const u8 *supp_oper_classes,
 				size_t supp_oper_classes_len);
+	int (*tdls_enable_channel_switch)(
+		void *ctx, const u8 *addr, u8 oper_class,
+		const struct hostapd_freq_params *params);
+	int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
 #endif /* CONFIG_TDLS */
-	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, size_t kek_len,
+				  const u8 *kck, size_t kck_len,
 				  const u8 *replay_ctr);
 	int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
 };
@@ -150,8 +156,9 @@
 int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
 
 void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
-void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
-			    const u8 *ptk_kek);
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+			    const u8 *ptk_kck, size_t ptk_kck_len,
+			    const u8 *ptk_kek, size_t ptk_kek_len);
 
 #else /* CONFIG_NO_WPA */
 
@@ -404,6 +411,10 @@
 void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
 const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+				u8 oper_class,
+				struct hostapd_freq_params *freq_params);
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
 
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
 
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 3b3c9d0..06dea05 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,8 +19,7 @@
 #ifdef CONFIG_IEEE80211R
 
 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
-		      const struct wpa_eapol_key *key,
-		      struct wpa_ptk *ptk, size_t ptk_len)
+		      const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
 {
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	const u8 *anonce = key->key_nonce;
@@ -43,13 +42,9 @@
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
-	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
-			  sm->bssid, sm->pmk_r1_name,
-			  (u8 *) ptk, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	return 0;
+	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+				 sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
+				 sm->key_mgmt, sm->pairwise_cipher);
 }
 
 
@@ -134,6 +129,7 @@
  * @anonce: ANonce or %NULL if not yet available
  * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
  * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octets
  * @target_ap: Target AP address
  * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
  * @ric_ies_len: Length of ric_ies buffer in octets
@@ -144,7 +140,8 @@
  */
 static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
 			       const u8 *anonce, const u8 *pmk_name,
-			       const u8 *kck, const u8 *target_ap,
+			       const u8 *kck, size_t kck_len,
+			       const u8 *target_ap,
 			       const u8 *ric_ies, size_t ric_ies_len,
 			       const u8 *ap_mdie)
 {
@@ -298,7 +295,7 @@
 		/* Information element count */
 		ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
 							       ric_ies_len);
-		if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+		if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
 			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
 			       ftie_pos, 2 + *ftie_len,
 			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
@@ -333,7 +330,7 @@
 	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
 	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
-			   sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
 	}
@@ -360,7 +357,7 @@
 	}
 
 	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, sm->bssid, NULL, 0, mdie);
+				    NULL, 0, sm->bssid, NULL, 0, mdie);
 	if (ft_ies) {
 		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
 				     ft_ies, ft_ies_len);
@@ -376,7 +373,7 @@
 			    const u8 *ric_ies, size_t ric_ies_len)
 {
 	u8 *ft_ies;
-	size_t ft_ies_len, ptk_len;
+	size_t ft_ies_len;
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
 	struct rsn_ftie *ftie;
@@ -478,16 +475,14 @@
 		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 
 	bssid = target_ap;
-	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);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
-			(u8 *) &sm->ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
+			      sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
+			      ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+		return -1;
 
 	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
-				    sm->pmk_r1_name, sm->ptk.kck, bssid,
+				    sm->pmk_r1_name,
+				    sm->ptk.kck, sm->ptk.kck_len, bssid,
 				    ric_ies, ric_ies_len,
 				    parse.mdie ? parse.mdie - 2 : NULL);
 	if (ft_ies) {
@@ -566,7 +561,8 @@
 		return -1;
 	}
 	gtk_len = gtk_elem_len - 19;
-	if (aes_unwrap(sm->ptk.kek, 16, gtk_len / 8, gtk_elem + 11, gtk)) {
+	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
+		       gtk)) {
 		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
 			   "decrypt GTK");
 		return -1;
@@ -645,8 +641,8 @@
 		return -1;
 	}
 
-	if (aes_unwrap(sm->ptk.kek, 16, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk))
-	{
+	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+		       igtk_elem + 9, igtk)) {
 		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
 			   "decrypt IGTK");
 		return -1;
@@ -677,7 +673,7 @@
 	struct rsn_mdie *mdie;
 	struct rsn_ftie *ftie;
 	unsigned int count;
-	u8 mic[16];
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
 
 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
 
@@ -770,7 +766,7 @@
 		return -1;
 	}
 
-	if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+	if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2,
@@ -839,7 +835,7 @@
 	}
 
 	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, target_ap, NULL, 0, mdie);
+				    NULL, 0, target_ap, NULL, 0, mdie);
 	if (ft_ies) {
 		sm->over_the_ds_in_progress = 1;
 		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index dd5ddfb..965a9c1 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
 /*
  * Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -23,6 +23,7 @@
 	size_t pmk_len;
 	struct wpa_ptk ptk, tptk;
 	int ptk_set, tptk_set;
+	unsigned int msg_3_of_4_ok:1;
 	u8 snonce[WPA_NONCE_LEN];
 	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
 	int renew_snonce;
@@ -92,6 +93,7 @@
 #ifdef CONFIG_TDLS
 	struct wpa_tdls_peer *tdls;
 	int tdls_prohibited;
+	int tdls_chan_switch_prohibited;
 	int tdls_disabled;
 
 	/* The driver supports TDLS */
@@ -102,6 +104,9 @@
 	 * to it via tdls_mgmt.
 	 */
 	int tdls_external_setup;
+
+	/* The driver supports TDLS channel switching */
+	int tdls_chan_switch;
 #endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
@@ -250,18 +255,20 @@
 {
 	if (!sm->ctx->set_rekey_offload)
 		return;
-	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
-				   sm->ptk.kck, sm->rx_replay_counter);
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, sm->ptk.kek_len,
+				   sm->ptk.kck, sm->ptk.kck_len,
+				   sm->rx_replay_counter);
 }
 
 #ifdef CONFIG_TDLS
 static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
 				       int *tdls_supported,
-				       int *tdls_ext_setup)
+				       int *tdls_ext_setup,
+				       int *tdls_chan_switch)
 {
 	if (sm->ctx->tdls_get_capa)
 		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
-					      tdls_ext_setup);
+					      tdls_ext_setup, tdls_chan_switch);
 	return -1;
 }
 
@@ -310,6 +317,26 @@
 						 supp_oper_classes_len);
 	return -1;
 }
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+				  u8 oper_class,
+				  const struct hostapd_freq_params *freq_params)
+{
+	if (sm->ctx->tdls_enable_channel_switch)
+		return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+							   oper_class,
+							   freq_params);
+	return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm->ctx->tdls_disable_channel_switch)
+		return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
+	return -1;
+}
 #endif /* CONFIG_TDLS */
 
 static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
@@ -322,7 +349,7 @@
 	return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
 }
 
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
 			int ver, const u8 *dest, u16 proto,
 			u8 *msg, size_t msg_len, u8 *key_mic);
 int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
@@ -336,8 +363,7 @@
 			       struct wpa_ptk *ptk);
 
 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
-		      const struct wpa_eapol_key *key,
-		      struct wpa_ptk *ptk, size_t ptk_len);
+		      const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
 
 void wpa_tdls_assoc(struct wpa_sm *sm);
 void wpa_tdls_disassoc(struct wpa_sm *sm);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 51876ed..0c37b35 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -30,6 +30,9 @@
 {
 	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
 		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+	if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
+	    wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
+		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
 	else
 		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
 }
@@ -173,6 +176,8 @@
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
+	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
 	} else {
@@ -506,12 +511,14 @@
 			ie->rsn_ie_len = pos[1] + 2;
 			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
 				    ie->rsn_ie, ie->rsn_ie_len);
-		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
+			   pos[1] >= sizeof(struct rsn_mdie)) {
 			ie->mdie = pos;
 			ie->mdie_len = pos[1] + 2;
 			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
 				    ie->mdie, ie->mdie_len);
-		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
+			   pos[1] >= sizeof(struct rsn_ftie)) {
 			ie->ftie = pos;
 			ie->ftie_len = pos[1] + 2;
 			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
@@ -546,15 +553,16 @@
 		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
 			ie->ext_supp_rates = pos;
 			ie->ext_supp_rates_len = pos[1] + 2;
-		} else if (*pos == WLAN_EID_HT_CAP) {
+		} else if (*pos == WLAN_EID_HT_CAP &&
+			   pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
 			ie->ht_capabilities = pos + 2;
-			ie->ht_capabilities_len = pos[1];
 		} else if (*pos == WLAN_EID_VHT_AID) {
 			if (pos[1] >= 2)
 				ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
-		} else if (*pos == WLAN_EID_VHT_CAP) {
+		} else if (*pos == WLAN_EID_VHT_CAP &&
+			   pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+		{
 			ie->vht_capabilities = pos + 2;
-			ie->vht_capabilities_len = pos[1];
 		} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
 			ie->qosinfo = pos[2];
 		} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 0fc42cc..fe95af0 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -50,9 +50,7 @@
 	const u8 *ext_supp_rates;
 	size_t ext_supp_rates_len;
 	const u8 *ht_capabilities;
-	size_t ht_capabilities_len;
 	const u8 *vht_capabilities;
-	size_t vht_capabilities_len;
 	const u8 *supp_channels;
 	size_t supp_channels_len;
 	const u8 *supp_oper_classes;
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index facdd65..533286c 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -731,8 +731,6 @@
 	if (conn->state != SERVER_HELLO) {
 		keys->server_random = conn->server_random;
 		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
 	}
 
 	return 0;
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 839eb90..d192f44 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -432,7 +432,6 @@
 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
 	size_t rlen, hlen, clen;
 	u8 hash[100], *hpos;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 
 	pos = *msgpos;
 
@@ -505,21 +504,17 @@
 	} else {
 #endif /* CONFIG_TLSV12 */
 
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify.md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
-		{
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			conn->verify.md5_cert = NULL;
-			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
-			conn->verify.sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_cert == NULL ||
+	    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_cert = NULL;
+		crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+		conn->verify.sha1_cert = NULL;
+		return -1;
+	}
+	hpos += MD5_MAC_LEN;
 
 	conn->verify.md5_cert = NULL;
 	hlen = SHA1_MAC_LEN;
@@ -532,8 +527,7 @@
 	}
 	conn->verify.sha1_cert = NULL;
 
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
+	hlen += MD5_MAC_LEN;
 
 #ifdef CONFIG_TLSV12
 	}
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index ced28cf..dabc12a 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -366,23 +366,20 @@
 {
 	u8 *hpos;
 	size_t hlen;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 	struct crypto_hash *ctx;
 
 	hpos = hash;
 
-	if (alg == SIGN_ALG_RSA) {
-		ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
-		if (ctx == NULL)
-			return -1;
-		crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
-		crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
-		crypto_hash_update(ctx, server_params, server_params_len);
-		hlen = MD5_MAC_LEN;
-		if (crypto_hash_finish(ctx, hash, &hlen) < 0)
-			return -1;
-		hpos += hlen;
-	}
+	ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	if (ctx == NULL)
+		return -1;
+	crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+	crypto_hash_update(ctx, server_params, server_params_len);
+	hlen = MD5_MAC_LEN;
+	if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+		return -1;
+	hpos += hlen;
 
 	ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
 	if (ctx == NULL)
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 93ae488..4df756f 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -627,8 +627,6 @@
 	if (conn->state != SERVER_HELLO) {
 		keys->server_random = conn->server_random;
 		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
 	}
 
 	return 0;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 310966c..0f237ba 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -775,7 +775,6 @@
 	u8 type;
 	size_t hlen;
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 	u8 alert;
 
 	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
@@ -883,21 +882,17 @@
 	} else {
 #endif /* CONFIG_TLSV12 */
 
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify.md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
-		{
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_INTERNAL_ERROR);
-			conn->verify.md5_cert = NULL;
-			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
-			conn->verify.sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_cert == NULL ||
+	    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_cert = NULL;
+		crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+		conn->verify.sha1_cert = NULL;
+		return -1;
+	}
+	hpos += MD5_MAC_LEN;
 
 	conn->verify.md5_cert = NULL;
 	hlen = SHA1_MAC_LEN;
@@ -910,8 +905,7 @@
 	}
 	conn->verify.sha1_cert = NULL;
 
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
+	hlen += MD5_MAC_LEN;
 
 #ifdef CONFIG_TLSV12
 	}
diff --git a/src/utils/bitfield.c b/src/utils/bitfield.c
index f90e4be..8dcec39 100644
--- a/src/utils/bitfield.c
+++ b/src/utils/bitfield.c
@@ -76,11 +76,11 @@
 int bitfield_get_first_zero(struct bitfield *bf)
 {
 	size_t i;
-	for (i = 0; i <= (bf->max_bits + 7) / 8; i++) {
+	for (i = 0; i < (bf->max_bits + 7) / 8; i++) {
 		if (bf->bits[i] != 0xff)
 			break;
 	}
-	if (i > (bf->max_bits + 7) / 8)
+	if (i == (bf->max_bits + 7) / 8)
 		return -1;
 	i = i * 8 + first_zero(bf->bits[i]);
 	if (i >= bf->max_bits)
diff --git a/src/utils/common.c b/src/utils/common.c
index 182c6a8..5cf0d57 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -8,6 +8,7 @@
 
 #include "includes.h"
 
+#include "common/ieee802_11_defs.h"
 #include "common.h"
 
 
@@ -36,6 +37,25 @@
 }
 
 
+static const char * hwaddr_parse(const char *txt, u8 *addr)
+{
+	size_t i;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		int a;
+
+		a = hex2byte(txt);
+		if (a < 0)
+			return NULL;
+		txt += 2;
+		addr[i] = a;
+		if (i < ETH_ALEN - 1 && *txt++ != ':')
+			return NULL;
+	}
+	return txt;
+}
+
+
 /**
  * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
  * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
@@ -44,25 +64,46 @@
  */
 int hwaddr_aton(const char *txt, u8 *addr)
 {
-	int i;
+	return hwaddr_parse(txt, addr) ? 0 : -1;
+}
 
-	for (i = 0; i < 6; i++) {
-		int a, b;
 
-		a = hex2num(*txt++);
-		if (a < 0)
+/**
+ * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
+ * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
+ * @maskable: Flag to indicate whether a mask is allowed
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
+{
+	const char *r;
+
+	/* parse address part */
+	r = hwaddr_parse(txt, addr);
+	if (!r)
+		return -1;
+
+	/* check for optional mask */
+	if (*r == '\0' || isspace(*r)) {
+		/* no mask specified, assume default */
+		os_memset(mask, 0xff, ETH_ALEN);
+	} else if (maskable && *r == '/') {
+		/* mask specified and allowed */
+		r = hwaddr_parse(r + 1, mask);
+		/* parser error? */
+		if (!r)
 			return -1;
-		b = hex2num(*txt++);
-		if (b < 0)
-			return -1;
-		*addr++ = (a << 4) | b;
-		if (i < 5 && *txt++ != ':')
-			return -1;
+	} else {
+		/* mask specified but not allowed or trailing garbage */
+		return -1;
 	}
 
 	return 0;
 }
 
+
 /**
  * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
  * @txt: MAC address as a string (e.g., "001122334455")
@@ -144,6 +185,30 @@
 }
 
 
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
+{
+	size_t i;
+	int print_mask = 0;
+	int res;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if (mask[i] != 0xff) {
+			print_mask = 1;
+			break;
+		}
+	}
+
+	if (print_mask)
+		res = os_snprintf(buf, len, MACSTR "/" MACSTR,
+				  MAC2STR(addr), MAC2STR(mask));
+	else
+		res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
+	if (os_snprintf_error(len, res))
+		return -1;
+	return res;
+}
+
+
 /**
  * inc_byte_array - Increment arbitrary length byte array by one
  * @counter: Pointer to byte array
@@ -213,6 +278,31 @@
 	return ret;
 }
 
+
+int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
+			 char sep)
+{
+	size_t i;
+	char *pos = buf, *end = buf + buf_size;
+	int ret;
+
+	if (buf_size == 0)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		ret = os_snprintf(pos, end - pos, "%02x%c",
+				  data[i], sep);
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+	pos[-1] = '\0';
+	return pos - buf;
+}
+
+
 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
 				    size_t len, int uppercase)
 {
@@ -520,7 +610,7 @@
  */
 const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
 {
-	static char ssid_txt[32 * 4 + 1];
+	static char ssid_txt[SSID_MAX_LEN * 4 + 1];
 
 	if (ssid == NULL) {
 		ssid_txt[0] = '\0';
@@ -912,3 +1002,95 @@
 	*context = end;
 	return pos;
 }
+
+
+size_t utf8_unescape(const char *inp, size_t in_size,
+		     char *outp, size_t out_size)
+{
+	size_t res_size = 0;
+
+	if (!inp || !outp)
+		return 0;
+
+	if (!in_size)
+		in_size = os_strlen(inp);
+
+	/* Advance past leading single quote */
+	if (*inp == '\'' && in_size) {
+		inp++;
+		in_size--;
+	}
+
+	while (in_size--) {
+		if (res_size >= out_size)
+			return 0;
+
+		switch (*inp) {
+		case '\'':
+			/* Terminate on bare single quote */
+			*outp = '\0';
+			return res_size;
+
+		case '\\':
+			if (!in_size--)
+				return 0;
+			inp++;
+			/* fall through */
+
+		default:
+			*outp++ = *inp++;
+			res_size++;
+		}
+	}
+
+	/* NUL terminate if space allows */
+	if (res_size < out_size)
+		*outp = '\0';
+
+	return res_size;
+}
+
+
+size_t utf8_escape(const char *inp, size_t in_size,
+		   char *outp, size_t out_size)
+{
+	size_t res_size = 0;
+
+	if (!inp || !outp)
+		return 0;
+
+	/* inp may or may not be NUL terminated, but must be if 0 size
+	 * is specified */
+	if (!in_size)
+		in_size = os_strlen(inp);
+
+	while (in_size--) {
+		if (res_size++ >= out_size)
+			return 0;
+
+		switch (*inp) {
+		case '\\':
+		case '\'':
+			if (res_size++ >= out_size)
+				return 0;
+			*outp++ = '\\';
+			/* fall through */
+
+		default:
+			*outp++ = *inp++;
+			break;
+		}
+	}
+
+	/* NUL terminate if space allows */
+	if (res_size < out_size)
+		*outp = '\0';
+
+	return res_size;
+}
+
+
+int is_ctrl_char(char c)
+{
+	return c > 0 && c < 32;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 7eca409..88318f5 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -164,6 +164,7 @@
 #define be_to_host16(n) wpa_swap_16(n)
 #define host_to_be16(n) wpa_swap_16(n)
 #define le_to_host32(n) (n)
+#define host_to_le32(n) (n)
 #define be_to_host32(n) wpa_swap_32(n)
 #define host_to_be32(n) wpa_swap_32(n)
 
@@ -471,6 +472,7 @@
 #endif /* __must_check */
 
 int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
 int hwaddr_compact_aton(const char *txt, u8 *addr);
 int hwaddr_aton2(const char *txt, u8 *addr);
 int hex2byte(const char *hex);
@@ -478,10 +480,14 @@
 void inc_byte_array(u8 *counter, size_t len);
 void wpa_get_ntp_timestamp(u8 *buf);
 int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
+int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
+			 char sep);
 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 			       size_t len);
 
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+
 #ifdef CONFIG_NATIVE_WINDOWS
 void wpa_unicode2ascii_inplace(TCHAR *str);
 TCHAR * wpa_strdup_tchar(const char *str);
@@ -544,6 +550,11 @@
 int random_mac_addr_keep_oui(u8 *addr);
 
 char * str_token(char *str, const char *delim, char **context);
+size_t utf8_escape(const char *inp, size_t in_size,
+		   char *outp, size_t out_size);
+size_t utf8_unescape(const char *inp, size_t in_size,
+		     char *outp, size_t out_size);
+int is_ctrl_char(char c);
 
 
 /*
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 0f7086e..f929dcd 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -242,8 +242,10 @@
 	eloop_trace_sock_remove_ref(table);
 	tmp = os_realloc_array(table->table, table->count + 1,
 			       sizeof(struct eloop_sock));
-	if (tmp == NULL)
+	if (tmp == NULL) {
+		eloop_trace_sock_add_ref(table);
 		return -1;
+	}
 
 	tmp[table->count].sock = sock;
 	tmp[table->count].eloop_data = eloop_data;
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index 0c18269..653eb54 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -855,8 +855,10 @@
 	struct http_cert hcert;
 	int ret;
 
-	if (ctx->cert_cb == NULL)
+	if (ctx->cert_cb == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__);
 		return 0;
+	}
 
 	if (0) {
 		BIO *out;
@@ -950,7 +952,8 @@
 	ssl_ctx = ssl->ctx;
 	ctx = SSL_CTX_get_app_data(ssl_ctx);
 
-	wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify");
+	wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d",
+		   preverify_ok);
 
 	err = X509_STORE_CTX_get_error(x509_ctx);
 	err_str = X509_verify_cert_error_string(err);
@@ -1084,7 +1087,7 @@
 
 		if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) {
 			tls_show_errors(__func__,
-					"OpenSSL: Could not add issuer to certificate store\n");
+					"OpenSSL: Could not add issuer to certificate store");
 		}
 		certs = sk_X509_new_null();
 		if (certs) {
@@ -1093,17 +1096,17 @@
 			if (cert && !sk_X509_push(certs, cert)) {
 				tls_show_errors(
 					__func__,
-					"OpenSSL: Could not add issuer to OCSP responder trust store\n");
+					"OpenSSL: Could not add issuer to OCSP responder trust store");
 				X509_free(cert);
 				sk_X509_free(certs);
 				certs = NULL;
 			}
-			if (ctx->peer_issuer_issuer) {
+			if (certs && ctx->peer_issuer_issuer) {
 				cert = X509_dup(ctx->peer_issuer_issuer);
 				if (cert && !sk_X509_push(certs, cert)) {
 					tls_show_errors(
 						__func__,
-						"OpenSSL: Could not add issuer to OCSP responder trust store\n");
+						"OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
 					X509_free(cert);
 				}
 			}
@@ -1249,9 +1252,14 @@
 			      const char *client_key)
 {
 	CURL *curl;
+#ifdef EAP_TLS_OPENSSL
+	const char *extra = " tls=openssl";
+#else /* EAP_TLS_OPENSSL */
+	const char *extra = "";
+#endif /* EAP_TLS_OPENSSL */
 
 	wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s "
-		   "username=%s", address, ca_fname, username);
+		   "username=%s%s", address, ca_fname, username, extra);
 
 	curl = curl_easy_init();
 	if (curl == NULL)
diff --git a/src/utils/list.h b/src/utils/list.h
index 6881130..ee2f485 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -17,6 +17,8 @@
 	struct dl_list *prev;
 };
 
+#define DL_LIST_HEAD_INIT(l) { &(l), &(l) }
+
 static inline void dl_list_init(struct dl_list *list)
 {
 	list->next = list;
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 523a4d0..e0c1125 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -26,7 +26,7 @@
 #include "trace.h"
 #include "list.h"
 
-static struct dl_list alloc_list;
+static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
 
 #define ALLOC_MAGIC 0xa84ef1b2
 #define FREED_MAGIC 0x67fd487a
@@ -321,9 +321,6 @@
 	capset(&header, &cap);
 #endif /* ANDROID */
 
-#ifdef WPA_TRACE
-	dl_list_init(&alloc_list);
-#endif /* WPA_TRACE */
 	return 0;
 }
 
@@ -467,9 +464,105 @@
 
 #ifdef WPA_TRACE
 
+#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
+char wpa_trace_fail_func[256] = { 0 };
+unsigned int wpa_trace_fail_after;
+
+static int testing_fail_alloc(void)
+{
+	const char *func[WPA_TRACE_LEN];
+	size_t i, res, len;
+	char *pos, *next;
+	int match;
+
+	if (!wpa_trace_fail_after)
+		return 0;
+
+	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
+	i = 0;
+	if (i < res && os_strcmp(func[i], __func__) == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_malloc") == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_calloc") == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_realloc") == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
+		i++;
+	if (i < res && os_strcmp(func[i], "os_strdup") == 0)
+		i++;
+
+	pos = wpa_trace_fail_func;
+
+	match = 0;
+	while (i < res) {
+		int allow_skip = 1;
+		int maybe = 0;
+
+		if (*pos == '=') {
+			allow_skip = 0;
+			pos++;
+		} else if (*pos == '?') {
+			maybe = 1;
+			pos++;
+		}
+		next = os_strchr(pos, ';');
+		if (next)
+			len = next - pos;
+		else
+			len = os_strlen(pos);
+		if (os_memcmp(pos, func[i], len) != 0) {
+			if (maybe && next) {
+				pos = next + 1;
+				continue;
+			}
+			if (allow_skip) {
+				i++;
+				continue;
+			}
+			return 0;
+		}
+		if (!next) {
+			match = 1;
+			break;
+		}
+		pos = next + 1;
+		i++;
+	}
+	if (!match)
+		return 0;
+
+	wpa_trace_fail_after--;
+	if (wpa_trace_fail_after == 0) {
+		wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
+			   wpa_trace_fail_func);
+		for (i = 0; i < res; i++)
+			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
+				   (int) i, func[i]);
+		return 1;
+	}
+
+	return 0;
+}
+
+#else
+
+static inline int testing_fail_alloc(void)
+{
+	return 0;
+}
+#endif
+
 void * os_malloc(size_t size)
 {
 	struct os_alloc_trace *a;
+
+	if (testing_fail_alloc())
+		return NULL;
+
 	a = malloc(sizeof(*a) + size);
 	if (a == NULL)
 		return NULL;
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 57ee132..296ea13 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -12,6 +12,7 @@
 #include <wincrypt.h>
 
 #include "os.h"
+#include "common.h"
 
 void os_sleep(os_time_t sec, os_time_t usec)
 {
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 7403c08..8484d27 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -160,7 +160,7 @@
 	if (abfd == NULL)
 		return;
 
-	data.pc = (bfd_vma) pc;
+	data.pc = (bfd_hostptr_t) pc;
 	data.found = FALSE;
 	bfd_map_over_sections(abfd, find_addr_sect, &data);
 
@@ -201,7 +201,7 @@
 	if (abfd == NULL)
 		return NULL;
 
-	data.pc = (bfd_vma) pc;
+	data.pc = (bfd_hostptr_t) pc;
 	data.found = FALSE;
 	bfd_map_over_sections(abfd, find_addr_sect, &data);
 
@@ -243,6 +243,53 @@
 	wpa_trace_bfd_addr(pc);
 }
 
+
+size_t wpa_trace_calling_func(const char *buf[], size_t len)
+{
+	bfd *abfd;
+	void *btrace_res[WPA_TRACE_LEN];
+	int i, btrace_num;
+	size_t pos = 0;
+
+	if (len == 0)
+		return 0;
+	if (len > WPA_TRACE_LEN)
+		len = WPA_TRACE_LEN;
+
+	wpa_trace_bfd_init();
+	abfd = cached_abfd;
+	if (!abfd)
+		return 0;
+
+	btrace_num = backtrace(btrace_res, len);
+	if (btrace_num < 1)
+		return 0;
+
+	for (i = 0; i < btrace_num; i++) {
+		struct bfd_data data;
+
+		data.pc = (bfd_hostptr_t) btrace_res[i];
+		data.found = FALSE;
+		bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+		while (data.found) {
+			if (data.function &&
+			    (pos > 0 ||
+			     os_strcmp(data.function, __func__) != 0)) {
+				buf[pos++] = data.function;
+				if (pos == len)
+					return pos;
+			}
+
+			data.found = bfd_find_inliner_info(abfd, &data.filename,
+							   &data.function,
+							   &data.line);
+		}
+	}
+
+	return pos;
+}
+
 #else /* WPA_TRACE_BFD */
 
 #define wpa_trace_bfd_init() do { } while (0)
diff --git a/src/utils/trace.h b/src/utils/trace.h
index 38f43fb..43ed86c 100644
--- a/src/utils/trace.h
+++ b/src/utils/trace.h
@@ -40,6 +40,7 @@
 			dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
 	} while (0)
 void wpa_trace_check_ref(const void *addr);
+size_t wpa_trace_calling_func(const char *buf[], size_t len);
 
 #else /* WPA_TRACE */
 
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index 9a9ec40..b2c7e08 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -1,6 +1,6 @@
 /*
  * utils module tests
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,9 +9,11 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "common/ieee802_11_defs.h"
 #include "utils/bitfield.h"
 #include "utils/ext_password.h"
 #include "utils/trace.h"
+#include "utils/base64.h"
 
 
 struct printf_test_data {
@@ -84,6 +86,15 @@
 		}
 	}
 
+	if (printf_decode(bin, 3, "abcde") != 2)
+		errors++;
+
+	if (printf_decode(bin, 3, "\\xa") != 1 || bin[0] != 10)
+		errors++;
+
+	if (printf_decode(bin, 3, "\\a") != 1 || bin[0] != 'a')
+		errors++;
+
 	if (errors) {
 		wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors);
 		return -1;
@@ -167,6 +178,17 @@
 
 	bitfield_free(bf);
 
+	bf = bitfield_alloc(8);
+	if (bf == NULL)
+		return -1;
+	if (bitfield_get_first_zero(bf) != 0)
+		errors++;
+	for (i = 0; i < 8; i++)
+		bitfield_set(bf, i);
+	if (bitfield_get_first_zero(bf) != -1)
+		errors++;
+	bitfield_free(bf);
+
 	if (errors) {
 		wpa_printf(MSG_ERROR, "%d bitfield test(s) failed", errors);
 		return -1;
@@ -249,6 +271,153 @@
 }
 
 
+static int base64_tests(void)
+{
+	int errors = 0;
+	unsigned char *res;
+	size_t res_len;
+
+	wpa_printf(MSG_INFO, "base64 tests");
+
+	res = base64_encode((const unsigned char *) "", ~0, &res_len);
+	if (res) {
+		errors++;
+		os_free(res);
+	}
+
+	res = base64_encode((const unsigned char *) "=", 1, &res_len);
+	if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' ||
+	    res[2] != '=' || res[3] != '=' || res[4] != '\n')
+		errors++;
+	os_free(res);
+
+	res = base64_encode((const unsigned char *) "=", 1, NULL);
+	if (!res || res[0] != 'P' || res[1] != 'Q' ||
+	    res[2] != '=' || res[3] != '=' || res[4] != '\n')
+		errors++;
+	os_free(res);
+
+	res = base64_decode((const unsigned char *) "", 0, &res_len);
+	if (res) {
+		errors++;
+		os_free(res);
+	}
+
+	res = base64_decode((const unsigned char *) "a", 1, &res_len);
+	if (res) {
+		errors++;
+		os_free(res);
+	}
+
+	res = base64_decode((const unsigned char *) "====", 4, &res_len);
+	if (res) {
+		errors++;
+		os_free(res);
+	}
+
+	res = base64_decode((const unsigned char *) "PQ==", 4, &res_len);
+	if (!res || res_len != 1 || res[0] != '=')
+		errors++;
+	os_free(res);
+
+	res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len);
+	if (!res || res_len != 1 || res[0] != '=')
+		errors++;
+	os_free(res);
+
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d base64 test(s) failed", errors);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int common_tests(void)
+{
+	char buf[3];
+	u8 addr[ETH_ALEN] = { 1, 2, 3, 4, 5, 6 };
+	u8 bin[3];
+	int errors = 0;
+	struct wpa_freq_range_list ranges;
+	size_t len;
+	const char *txt;
+	u8 ssid[255];
+
+	wpa_printf(MSG_INFO, "common tests");
+
+	if (hwaddr_mask_txt(buf, 3, addr, addr) != -1)
+		errors++;
+
+	if (wpa_scnprintf(buf, 0, "hello") != 0 ||
+	    wpa_scnprintf(buf, 3, "hello") != 2)
+		errors++;
+
+	if (wpa_snprintf_hex(buf, 0, addr, ETH_ALEN) != 0 ||
+	    wpa_snprintf_hex(buf, 3, addr, ETH_ALEN) != 2)
+		errors++;
+
+	if (merge_byte_arrays(bin, 3, addr, ETH_ALEN, NULL, 0) != 3 ||
+	    merge_byte_arrays(bin, 3, NULL, 0, addr, ETH_ALEN) != 3)
+		errors++;
+
+	if (dup_binstr(NULL, 0) != NULL)
+		errors++;
+
+	if (freq_range_list_includes(NULL, 0) != 0)
+		errors++;
+
+	os_memset(&ranges, 0, sizeof(ranges));
+	if (freq_range_list_parse(&ranges, "") != 0 ||
+	    freq_range_list_includes(&ranges, 0) != 0 ||
+	    freq_range_list_str(&ranges) != NULL)
+		errors++;
+
+	if (utf8_unescape(NULL, 0, buf, sizeof(buf)) != 0 ||
+	    utf8_unescape("a", 1, NULL, 0) != 0 ||
+	    utf8_unescape("a\\", 2, buf, sizeof(buf)) != 0 ||
+	    utf8_unescape("abcde", 5, buf, sizeof(buf)) != 0 ||
+	    utf8_unescape("abc", 3, buf, 3) != 3)
+		errors++;
+
+	if (utf8_unescape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+		errors++;
+
+	if (utf8_unescape("\\b", 2, buf, sizeof(buf)) != 1 || buf[0] != 'b')
+		errors++;
+
+	if (utf8_escape(NULL, 0, buf, sizeof(buf)) != 0 ||
+	    utf8_escape("a", 1, NULL, 0) != 0 ||
+	    utf8_escape("abcde", 5, buf, sizeof(buf)) != 0 ||
+	    utf8_escape("a\\bcde", 6, buf, sizeof(buf)) != 0 ||
+	    utf8_escape("ab\\cde", 6, buf, sizeof(buf)) != 0 ||
+	    utf8_escape("abc\\de", 6, buf, sizeof(buf)) != 0 ||
+	    utf8_escape("abc", 3, buf, 3) != 3)
+		errors++;
+
+	if (utf8_escape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+		errors++;
+
+	os_memset(ssid, 0, sizeof(ssid));
+	txt = wpa_ssid_txt(ssid, sizeof(ssid));
+	len = os_strlen(txt);
+	/* Verify that SSID_MAX_LEN * 4 buffer limit is enforced. */
+	if (len != SSID_MAX_LEN * 4) {
+		wpa_printf(MSG_ERROR,
+			   "Unexpected wpa_ssid_txt() result with too long SSID");
+		errors++;
+	}
+
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d common test(s) failed", errors);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 int utils_module_tests(void)
 {
 	int ret = 0;
@@ -259,6 +428,8 @@
 	    ext_password_tests() < 0 ||
 	    trace_tests() < 0 ||
 	    bitfield_tests() < 0 ||
+	    base64_tests() < 0 ||
+	    common_tests() < 0 ||
 	    int_array_tests() < 0)
 		ret = -1;
 
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index b257b36..7aafa0a 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -205,6 +205,15 @@
 }
 
 
+void wpabuf_clear_free(struct wpabuf *buf)
+{
+	if (buf) {
+		os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
+		wpabuf_free(buf);
+	}
+}
+
+
 void * wpabuf_put(struct wpabuf *buf, size_t len)
 {
 	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index dbce925..c3ef1ba 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -32,6 +32,7 @@
 struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
 struct wpabuf * wpabuf_dup(const struct wpabuf *src);
 void wpabuf_free(struct wpabuf *buf);
+void wpabuf_clear_free(struct wpabuf *buf);
 void * wpabuf_put(struct wpabuf *buf, size_t len);
 struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
 struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
diff --git a/src/wps/Makefile b/src/wps/Makefile
index adfd3df..4806fe8 100644
--- a/src/wps/Makefile
+++ b/src/wps/Makefile
@@ -1,8 +1,41 @@
-all:
-	@echo Nothing to be made.
+all: libwps.a
 
 clean:
-	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libwps.a
 
 install:
 	@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_P2P
+CFLAGS += -DCONFIG_WPS_OOB
+CFLAGS += -DCONFIG_WPS_NFC
+
+LIB_OBJS= \
+	http_client.o \
+	httpread.o \
+	http_server.o \
+	ndef.o \
+	upnp_xml.o \
+	wps_attr_build.o \
+	wps_attr_parse.o \
+	wps_attr_process.o \
+	wps.o \
+	wps_common.o \
+	wps_dev_attr.o \
+	wps_enrollee.o \
+	wps_er.o \
+	wps_er_ssdp.o \
+	wps_module_tests.o \
+	wps_registrar.o \
+	wps_upnp_ap.o \
+	wps_upnp.o \
+	wps_upnp_event.o \
+	wps_upnp_ssdp.o \
+	wps_upnp_web.o
+
+libwps.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 2c68be8..498f11f 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -618,7 +618,8 @@
 		if (str == NULL)
 			return pos - buf;
 		for (i = 0; i < attr.dev_name_len; i++) {
-			if (attr.dev_name[i] < 32)
+			if (attr.dev_name[i] == 0 ||
+			    is_ctrl_char(attr.dev_name[i]))
 				str[i] = '_';
 			else
 				str[i] = attr.dev_name[i];
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 0a7f65d..c88aaa4 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -9,6 +9,7 @@
 #ifndef WPS_H
 #define WPS_H
 
+#include "common/ieee802_11_defs.h"
 #include "wps_defs.h"
 
 /**
@@ -44,7 +45,7 @@
  * @cred_attr_len: Length of cred_attr in octets
  */
 struct wps_credential {
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 	u16 auth_type;
 	u16 encr_type;
@@ -623,7 +624,7 @@
 	 * Credentials. In addition, AP uses it when acting as an Enrollee to
 	 * notify Registrar of the current configuration.
 	 */
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 
 	/**
 	 * ssid_len - Length of ssid in octets
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 40bc1ad..11a967b 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -447,25 +447,55 @@
 		break;
 	case ATTR_MANUFACTURER:
 		attr->manufacturer = pos;
-		attr->manufacturer_len = len;
+		if (len > WPS_MANUFACTURER_MAX_LEN)
+			attr->manufacturer_len = WPS_MANUFACTURER_MAX_LEN;
+		else
+			attr->manufacturer_len = len;
 		break;
 	case ATTR_MODEL_NAME:
 		attr->model_name = pos;
-		attr->model_name_len = len;
+		if (len > WPS_MODEL_NAME_MAX_LEN)
+			attr->model_name_len = WPS_MODEL_NAME_MAX_LEN;
+		else
+			attr->model_name_len = len;
 		break;
 	case ATTR_MODEL_NUMBER:
 		attr->model_number = pos;
-		attr->model_number_len = len;
+		if (len > WPS_MODEL_NUMBER_MAX_LEN)
+			attr->model_number_len = WPS_MODEL_NUMBER_MAX_LEN;
+		else
+			attr->model_number_len = len;
 		break;
 	case ATTR_SERIAL_NUMBER:
 		attr->serial_number = pos;
-		attr->serial_number_len = len;
+		if (len > WPS_SERIAL_NUMBER_MAX_LEN)
+			attr->serial_number_len = WPS_SERIAL_NUMBER_MAX_LEN;
+		else
+			attr->serial_number_len = len;
 		break;
 	case ATTR_DEV_NAME:
+		if (len > WPS_DEV_NAME_MAX_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: Ignore too long Device Name (len=%u)",
+				   len);
+			break;
+		}
 		attr->dev_name = pos;
 		attr->dev_name_len = len;
 		break;
 	case ATTR_PUBLIC_KEY:
+		/*
+		 * The Public Key attribute is supposed to be exactly 192 bytes
+		 * in length. Allow couple of bytes shorter one to try to
+		 * interoperate with implementations that do not use proper
+		 * zero-padding.
+		 */
+		if (len < 190 || len > 192) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: Ignore Public Key with unexpected length %u",
+				   len);
+			break;
+		}
 		attr->public_key = pos;
 		attr->public_key_len = len;
 		break;
@@ -485,6 +515,11 @@
 		attr->num_cred++;
 		break;
 	case ATTR_SSID:
+		if (len > SSID_MAX_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: Ignore too long SSID (len=%u)", len);
+			break;
+		}
 		attr->ssid = pos;
 		attr->ssid_len = len;
 		break;
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 222d485..c1ede6a 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -535,6 +535,9 @@
 #ifdef CONFIG_WPS_NFC
 		methods |= WPS_CONFIG_NFC_INTERFACE;
 #endif /* CONFIG_WPS_NFC */
+#ifdef CONFIG_P2P
+		methods |= WPS_CONFIG_P2PS;
+#endif /* CONFIG_P2P */
 	} else {
 		if (os_strstr(str, "ethernet"))
 			methods |= WPS_CONFIG_ETHERNET;
@@ -560,6 +563,8 @@
 			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
 		if (os_strstr(str, "physical_push_button"))
 			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+		if (os_strstr(str, "p2ps"))
+			methods |= WPS_CONFIG_P2PS;
 	}
 
 	return methods;
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index da005a4..4334155 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -41,6 +41,11 @@
 #define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
 #define WPS_OOB_DEVICE_PASSWORD_LEN 32
 #define WPS_OOB_PUBKEY_HASH_LEN 20
+#define WPS_DEV_NAME_MAX_LEN 32
+#define WPS_MANUFACTURER_MAX_LEN 64
+#define WPS_MODEL_NAME_MAX_LEN 32
+#define WPS_MODEL_NUMBER_MAX_LEN 32
+#define WPS_SERIAL_NUMBER_MAX_LEN 32
 
 /* Attribute Types */
 enum wps_attribute {
@@ -154,7 +159,8 @@
 	DEV_PW_REKEY = 0x0003,
 	DEV_PW_PUSHBUTTON = 0x0004,
 	DEV_PW_REGISTRAR_SPECIFIED = 0x0005,
-	DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007
+	DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007,
+	DEV_PW_P2PS_DEFAULT = 0x0008
 };
 
 /* Message Type */
@@ -244,6 +250,7 @@
 #define WPS_CONFIG_KEYPAD 0x0100
 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_P2PS 0x1000
 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
 #define WPS_CONFIG_PHY_DISPLAY 0x4008
 
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9f5a90c..89957b1 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -247,22 +247,48 @@
 
 static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
 {
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
-		   wps->wps->ap_auth_type);
+	u16 auth_type = wps->wps->ap_auth_type;
+
+	/*
+	 * Work around issues with Windows 7 WPS implementation not liking
+	 * multiple Authentication Type bits in M7 AP Settings attribute by
+	 * showing only the most secure option from current configuration.
+	 */
+	if (auth_type & WPS_AUTH_WPA2PSK)
+		auth_type = WPS_AUTH_WPA2PSK;
+	else if (auth_type & WPS_AUTH_WPAPSK)
+		auth_type = WPS_AUTH_WPAPSK;
+	else if (auth_type & WPS_AUTH_OPEN)
+		auth_type = WPS_AUTH_OPEN;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)", auth_type);
 	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
 	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, wps->wps->ap_auth_type);
+	wpabuf_put_be16(msg, auth_type);
 	return 0;
 }
 
 
 static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
 {
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
-		   wps->wps->ap_encr_type);
+	u16 encr_type = wps->wps->ap_encr_type;
+
+	/*
+	 * Work around issues with Windows 7 WPS implementation not liking
+	 * multiple Encryption Type bits in M7 AP Settings attribute by
+	 * showing only the most secure option from current configuration.
+	 */
+	if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
+		if (encr_type & WPS_ENCR_AES)
+			encr_type = WPS_ENCR_AES;
+		else if (encr_type & WPS_ENCR_TKIP)
+			encr_type = WPS_ENCR_TKIP;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)", encr_type);
 	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
 	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, wps->wps->ap_encr_type);
+	wpabuf_put_be16(msg, encr_type);
 	return 0;
 }
 
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 8ee1ea9..48b7e12 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -2578,6 +2578,7 @@
 
 	if (wps->dev_pw_id < 0x10 &&
 	    wps->dev_pw_id != DEV_PW_DEFAULT &&
+	    wps->dev_pw_id != DEV_PW_P2PS_DEFAULT &&
 	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
diff --git a/tests/Makefile b/tests/Makefile
index 9877bb0..782396a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,4 +1,4 @@
-TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs \
+TESTS=test-base64 test-md4 test-milenage \
 	test-rsa-sig-ver \
 	test-sha1 \
 	test-sha256 test-aes test-asn1 test-x509 test-x509v3 test-list test-rc4
@@ -59,15 +59,9 @@
 test-md4: test-md4.o $(LIBS)
 	$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
 
-test-md5: test-md5.o $(LIBS)
-	$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
-
 test-milenage: test-milenage.o $(LIBS)
 	$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
 
-test-ms_funcs: test-ms_funcs.o $(LIBS)
-	$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
-
 test-rc4: test-rc4.o $(LIBS)
 	$(LDO) $(LDFLAGS) -o $@ $^ $(LLIBS)
 
@@ -91,7 +85,6 @@
 	./test-aes
 	./test-list
 	./test-md4
-	./test-md5
 	./test-milenage
 	./test-rsa-sig-ver
 	./test-sha1
diff --git a/tests/ap-mgmt-fuzzer/Makefile b/tests/ap-mgmt-fuzzer/Makefile
new file mode 100644
index 0000000..141a6f6
--- /dev/null
+++ b/tests/ap-mgmt-fuzzer/Makefile
@@ -0,0 +1,81 @@
+all: ap-mgmt-fuzzer
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+SRC=../../src
+
+CFLAGS += -I$(SRC)
+CFLAGS += -I$(SRC)/utils
+CFLAGS += -DCONFIG_WNM
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_GAS
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DIEEE8021X_EAPOL
+CFLAGS += -DNEED_AP_MLME
+
+$(SRC)/utils/libutils.a:
+	$(MAKE) -C $(SRC)/utils
+
+$(SRC)/common/libcommon.a:
+	$(MAKE) -C $(SRC)/common
+
+$(SRC)/crypto/libcrypto.a:
+	$(MAKE) -C $(SRC)/crypto
+
+$(SRC)/tls/libtls.a:
+	$(MAKE) -C $(SRC)/tls
+
+$(SRC)/wps/libwps.a:
+	$(MAKE) -C $(SRC)/wps
+
+$(SRC)/eap_common/libeap_common.a:
+	$(MAKE) -C $(SRC)/eap_common
+
+$(SRC)/eap_server/libeap_server.a:
+	$(MAKE) -C $(SRC)/eap_server
+
+$(SRC)/l2_packet/libl2_packet.a:
+	$(MAKE) -C $(SRC)/l2_packet
+
+$(SRC)/eapol_auth/libeapol_auth.a:
+	$(MAKE) -C $(SRC)/eapol_auth
+
+$(SRC)/ap/libap.a:
+	$(MAKE) -C $(SRC)/ap
+
+$(SRC)/radius/libradius.a:
+	$(MAKE) -C $(SRC)/radius
+
+LIBS += $(SRC)/common/libcommon.a
+LIBS += $(SRC)/crypto/libcrypto.a
+LIBS += $(SRC)/tls/libtls.a
+LIBS += $(SRC)/wps/libwps.a
+LIBS += $(SRC)/eap_server/libeap_server.a
+LIBS += $(SRC)/eap_common/libeap_common.a
+LIBS += $(SRC)/l2_packet/libl2_packet.a
+LIBS += $(SRC)/ap/libap.a
+LIBS += $(SRC)/eapol_auth/libeapol_auth.a
+LIBS += $(SRC)/radius/libradius.a
+LIBS += $(SRC)/utils/libutils.a
+
+ELIBS += $(SRC)/crypto/libcrypto.a
+ELIBS += $(SRC)/tls/libtls.a
+
+ap-mgmt-fuzzer: ap-mgmt-fuzzer.o $(OBJS) $(LIBS)
+	$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
+
+clean:
+	$(MAKE) -C $(SRC) clean
+	rm -f ap-mgmt-fuzzer *~ *.o *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c b/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c
new file mode 100644
index 0000000..7d65af7
--- /dev/null
+++ b/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c
@@ -0,0 +1,116 @@
+/*
+ * hostapd - Management frame fuzzer
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "ap/hostapd.h"
+#include "ap/ieee802_11.h"
+
+
+struct wpa_driver_ops *wpa_drivers[] =
+{
+	NULL
+};
+
+
+struct arg_ctx {
+	const char *fname;
+	struct hostapd_iface iface;
+	struct hostapd_data hapd;
+	struct wpa_driver_ops driver;
+	struct hostapd_config iconf;
+	struct hostapd_bss_config conf;
+};
+
+
+static void test_send_mgmt(void *eloop_data, void *user_ctx)
+{
+	struct arg_ctx *ctx = eloop_data;
+	char *data;
+	size_t len;
+	struct hostapd_frame_info fi;
+
+	wpa_printf(MSG_INFO, "ap-mgmt-fuzzer: Send '%s'", ctx->fname);
+
+	data = os_readfile(ctx->fname, &len);
+	if (!data) {
+		wpa_printf(MSG_ERROR, "Could not read '%s'", ctx->fname);
+		goto out;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "fuzzer - WNM", data, len);
+
+	os_memset(&fi, 0, sizeof(fi));
+	ieee802_11_mgmt(&ctx->hapd, (u8 *) data, len, &fi);
+
+out:
+	os_free(data);
+	eloop_terminate();
+}
+
+
+static int init_hapd(struct arg_ctx *ctx)
+{
+	struct hostapd_data *hapd = &ctx->hapd;
+
+	hapd->driver = &ctx->driver;
+	os_memcpy(hapd->own_addr, "\x02\x00\x00\x00\x03\x00", ETH_ALEN);
+	hapd->iface = &ctx->iface;
+	hapd->iface->conf = hostapd_config_defaults();;
+	if (!hapd->iface->conf)
+		return -1;
+	hapd->iconf = hapd->iface->conf;
+	hapd->conf = hapd->iconf->bss[0];
+	hostapd_config_defaults_bss(hapd->conf);
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct arg_ctx ctx;
+	int ret = -1;
+
+	if (argc < 2) {
+		printf("usage: %s <file>\n", argv[0]);
+		return -1;
+	}
+
+	if (os_program_init())
+		return -1;
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	os_memset(&ctx, 0, sizeof(ctx));
+	ctx.fname = argv[1];
+	if (init_hapd(&ctx))
+		goto fail;
+
+	eloop_register_timeout(0, 0, test_send_mgmt, &ctx, NULL);
+
+	wpa_printf(MSG_DEBUG, "Starting eloop");
+	eloop_run();
+	wpa_printf(MSG_DEBUG, "eloop done");
+
+	ret = 0;
+fail:
+	hostapd_config_free(ctx.hapd.iconf);
+	eloop_destroy();
+	os_program_deinit();
+
+	return ret;
+}
diff --git a/tests/ap-mgmt-fuzzer/auth.dat b/tests/ap-mgmt-fuzzer/auth.dat
new file mode 100644
index 0000000..0eb36e5
--- /dev/null
+++ b/tests/ap-mgmt-fuzzer/auth.dat
Binary files differ
diff --git a/tests/ap-mgmt-fuzzer/probe-req.dat b/tests/ap-mgmt-fuzzer/probe-req.dat
new file mode 100644
index 0000000..a5fba77
--- /dev/null
+++ b/tests/ap-mgmt-fuzzer/probe-req.dat
Binary files differ
diff --git a/tests/eapol-fuzzer/Makefile b/tests/eapol-fuzzer/Makefile
new file mode 100644
index 0000000..f5a9a57
--- /dev/null
+++ b/tests/eapol-fuzzer/Makefile
@@ -0,0 +1,67 @@
+all: eapol-fuzzer
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+SRC=../../src
+
+CFLAGS += -I$(SRC)
+CFLAGS += -DIEEE8021X_EAPOL
+
+$(SRC)/utils/libutils.a:
+	$(MAKE) -C $(SRC)/utils
+
+$(SRC)/common/libcommon.a:
+	$(MAKE) -C $(SRC)/common
+
+$(SRC)/crypto/libcrypto.a:
+	$(MAKE) -C $(SRC)/crypto
+
+$(SRC)/tls/libtls.a:
+	$(MAKE) -C $(SRC)/tls
+
+$(SRC)/rsn_supp/librsn_supp.a:
+	$(MAKE) -C $(SRC)/rsn_supp
+
+$(SRC)/eapol_supp/libeapol_supp.a:
+	$(MAKE) -C $(SRC)/eapol_supp
+
+$(SRC)/eap_peer/libeap_peer.a:
+	$(MAKE) -C $(SRC)/eap_peer
+
+$(SRC)/eap_common/libeap_common.a:
+	$(MAKE) -C $(SRC)/eap_common
+
+$(SRC)/l2_packet/libl2_packet.a:
+	$(MAKE) -C $(SRC)/l2_packet
+
+LIBS += $(SRC)/common/libcommon.a
+LIBS += $(SRC)/crypto/libcrypto.a
+LIBS += $(SRC)/tls/libtls.a
+LIBS += $(SRC)/rsn_supp/librsn_supp.a
+LIBS += $(SRC)/eapol_supp/libeapol_supp.a
+LIBS += $(SRC)/eap_peer/libeap_peer.a
+LIBS += $(SRC)/eap_common/libeap_common.a
+LIBS += $(SRC)/l2_packet/libl2_packet.a
+LIBS += $(SRC)/utils/libutils.a
+
+ELIBS += $(SRC)/crypto/libcrypto.a
+ELIBS += $(SRC)/tls/libtls.a
+
+eapol-fuzzer: eapol-fuzzer.o $(LIBS)
+	$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
+
+clean:
+	$(MAKE) -C $(SRC) clean
+	rm -f eapol-fuzzer *~ *.o *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/tests/eapol-fuzzer/eap-req-identity.dat b/tests/eapol-fuzzer/eap-req-identity.dat
new file mode 100644
index 0000000..768b277
--- /dev/null
+++ b/tests/eapol-fuzzer/eap-req-identity.dat
Binary files differ
diff --git a/tests/eapol-fuzzer/eap-req-sim.dat b/tests/eapol-fuzzer/eap-req-sim.dat
new file mode 100644
index 0000000..eb854aa
--- /dev/null
+++ b/tests/eapol-fuzzer/eap-req-sim.dat
Binary files differ
diff --git a/tests/eapol-fuzzer/eapol-fuzzer.c b/tests/eapol-fuzzer/eapol-fuzzer.c
new file mode 100644
index 0000000..7429ee3
--- /dev/null
+++ b/tests/eapol-fuzzer/eapol-fuzzer.c
@@ -0,0 +1,211 @@
+/*
+ * wpa_supplicant - EAPOL fuzzer
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+
+
+struct arg_ctx {
+	const char *fname;
+	struct wpa_sm *wpa;
+	struct eapol_sm *eapol;
+};
+
+
+static void test_send_eapol(void *eloop_data, void *user_ctx)
+{
+	struct arg_ctx *ctx = eloop_data;
+	char *data;
+	size_t len;
+	u8 src[ETH_ALEN] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 };
+	u8 wpa_ie[200];
+	size_t wpa_ie_len;
+
+	wpa_printf(MSG_INFO, "eapol-fuzzer: Send '%s'", ctx->fname);
+
+	data = os_readfile(ctx->fname, &len);
+	if (!data) {
+		wpa_printf(MSG_ERROR, "Could not read '%s'", ctx->fname);
+		goto out;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "fuzzer - EAPOL", data, len);
+
+	eapol_sm_notify_portEnabled(ctx->eapol, TRUE);
+
+	wpa_sm_set_param(ctx->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+	wpa_sm_set_param(ctx->wpa, WPA_PARAM_RSN_ENABLED, 1);
+	wpa_sm_set_param(ctx->wpa, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
+	wpa_sm_set_param(ctx->wpa, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
+	wpa_sm_set_param(ctx->wpa, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
+
+	wpa_ie_len = sizeof(wpa_ie);
+	wpa_sm_set_assoc_wpa_ie_default(ctx->wpa, wpa_ie, &wpa_ie_len);
+
+	if (eapol_sm_rx_eapol(ctx->eapol, src, (u8 *) data, len) <= 0)
+		wpa_sm_rx_eapol(ctx->wpa, src, (u8 *) data, len);
+
+out:
+	os_free(data);
+	eloop_terminate();
+}
+
+
+static void * get_network_ctx(void *arg)
+{
+	return (void *) 1;
+}
+
+
+static void set_state(void *arg, enum wpa_states state)
+{
+}
+
+
+static void deauthenticate(void *arg, int reason_code)
+{
+}
+
+
+static u8 * alloc_eapol(void *arg, u8 type,
+			const void *data, u16 data_len,
+			size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = 2;
+	hdr->type = type;
+	hdr->length = host_to_be16(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+static int ether_send(void *arg, const u8 *dest, u16 proto,
+		      const u8 *buf, size_t len)
+{
+	return 0;
+}
+
+
+static int get_bssid(void *ctx, u8 *bssid)
+{
+	return -1;
+}
+
+
+static int eapol_send(void *ctx, int type, const u8 *buf, size_t len)
+{
+	return 0;
+}
+
+
+static int init_wpa(struct arg_ctx *arg)
+{
+	struct wpa_sm_ctx *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
+		return -1;
+	}
+
+	ctx->ctx = arg;
+	ctx->msg_ctx = arg;
+	ctx->get_network_ctx = get_network_ctx;
+	ctx->set_state = set_state;
+	ctx->deauthenticate = deauthenticate;
+	ctx->alloc_eapol = alloc_eapol;
+	ctx->ether_send = ether_send;
+	ctx->get_bssid = get_bssid;
+
+	arg->wpa = wpa_sm_init(ctx);
+	return arg->wpa ? 0 : -1;
+}
+
+
+static int init_eapol(struct arg_ctx *arg)
+{
+	struct eapol_ctx *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
+		return -1;
+	}
+
+	ctx->ctx = arg;
+	ctx->msg_ctx = arg;
+	ctx->eapol_send = eapol_send;
+
+	arg->eapol = eapol_sm_init(ctx);
+	return arg->eapol ? 0 : -1;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct arg_ctx ctx;
+	int ret = -1;
+
+	if (argc < 2) {
+		printf("usage: %s <file>\n", argv[0]);
+		return -1;
+	}
+
+	if (os_program_init())
+		return -1;
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	os_memset(&ctx, 0, sizeof(ctx));
+	ctx.fname = argv[1];
+	if (init_wpa(&ctx) || init_eapol(&ctx))
+		goto fail;
+
+	eloop_register_timeout(0, 0, test_send_eapol, &ctx, NULL);
+
+	wpa_printf(MSG_DEBUG, "Starting eloop");
+	eloop_run();
+	wpa_printf(MSG_DEBUG, "eloop done");
+
+	ret = 0;
+fail:
+	if (ctx.wpa)
+		wpa_sm_deinit(ctx.wpa);
+	if (ctx.eapol)
+		eapol_sm_deinit(ctx.eapol);
+
+	eloop_destroy();
+	os_program_deinit();
+
+	return ret;
+}
diff --git a/tests/eapol-fuzzer/eapol-key-m1.dat b/tests/eapol-fuzzer/eapol-key-m1.dat
new file mode 100644
index 0000000..937721c
--- /dev/null
+++ b/tests/eapol-fuzzer/eapol-key-m1.dat
Binary files differ
diff --git a/tests/hwsim/README b/tests/hwsim/README
index 8e82670..e68b0dc 100644
--- a/tests/hwsim/README
+++ b/tests/hwsim/README
@@ -65,6 +65,9 @@
 - libsqlite3-dev
 - libpcap-dev
 
+example-setup.txt provides more complete step-by-step example on how a
+test setup can be built.
+
 
 wpaspy
 ------
diff --git a/tests/hwsim/auth_serv/as.conf b/tests/hwsim/auth_serv/as.conf
index 8d9c78b..0d89b92 100644
--- a/tests/hwsim/auth_serv/as.conf
+++ b/tests/hwsim/auth_serv/as.conf
@@ -11,7 +11,7 @@
 ca_cert=auth_serv/ca.pem
 server_cert=auth_serv/server.pem
 private_key=auth_serv/server.key
-ocsp_stapling_response=auth_serv/ocsp-server-cache.der
+ocsp_stapling_response=LOGDIR/ocsp-server-cache.der
 server_id=server.w1.fi
 eap_sim_db=unix:/tmp/hlr_auc_gw.sock
 dh_file=auth_serv/dh.conf
diff --git a/tests/hwsim/auth_serv/as2.conf b/tests/hwsim/auth_serv/as2.conf
index 6261a09..d9ee031 100644
--- a/tests/hwsim/auth_serv/as2.conf
+++ b/tests/hwsim/auth_serv/as2.conf
@@ -11,7 +11,7 @@
 ca_cert=auth_serv/ca.pem
 server_cert=auth_serv/server.pem
 private_key=auth_serv/server.key
-ocsp_stapling_response=auth_serv/ocsp-server-cache.der
+ocsp_stapling_response=LOGDIR/ocsp-server-cache.der
 server_id=server2.w1.fi
 eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=LOGDIR/hostapd.db
 dh_file=auth_serv/dh.conf
diff --git a/tests/hwsim/auth_serv/eap_user.conf b/tests/hwsim/auth_serv/eap_user.conf
index 55569e2..4debe48 100644
--- a/tests/hwsim/auth_serv/eap_user.conf
+++ b/tests/hwsim/auth_serv/eap_user.conf
@@ -1,4 +1,5 @@
 "pwd user"	PWD	"secret password"
+"pwd-hash"	PWD	hash:e3718ece8ab74792cbbfffd316d2d19a
 "pwd.user@test123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.example.com"	PWD	"secret password"
 "gpsk user"	GPSK	"abcdefghijklmnop0123456789abcdef"
 "sake user"	SAKE	0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
@@ -47,6 +48,9 @@
 
 "020000000000"	MACACL	"020000000000"
 
+"020000000100"	MACACL	"020000000100"
+radius_accept_attr=89:s:macacl-cui-test
+
 "0232010000000000@ttls"	TTLS,AKA
 "0232010000000000@peap"	PEAP,AKA
 "0232010000000000@fast"	FAST,AKA
@@ -74,6 +78,8 @@
 "8"*		AKA'	[2]
 
 "pap user"	TTLS-PAP	"password"	[2]
+"pap-secret"	TTLS-PAP	"63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"	[2]
+"pap-secret@example.com"	TTLS-PAP	"63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"	[2]
 "chap user"	TTLS-CHAP	"password"	[2]
 "mschap user"	TTLS-MSCHAP	"password"	[2]
 "DOMAIN\mschapv2 user"	TTLS-MSCHAPV2	hash:8846f7eaee8fb117ad06bdd830b7586c	[2]
@@ -82,6 +88,9 @@
 "utf8-user-hash"	TTLS-MSCHAPV2	hash:bd5844fad2489992da7fe8c5a01559cf	[2]
 
 "user"	MSCHAPV2,MD5,GTC	"password"	[2]
+"user2"	MSCHAPV2,MD5,GTC	"password"	[2]
+"DOMAIN\user3"	MSCHAPV2	"password"	[2]
+"user-no-passwd"	MSCHAPV2,MD5,GTC	[2]
 "cert user"	TLS	[2]
 
 "hs20-deauth-test"	TTLS-MSCHAPV2	"password"	[2]
diff --git a/tests/hwsim/auth_serv/eap_user_vlan.conf b/tests/hwsim/auth_serv/eap_user_vlan.conf
new file mode 100644
index 0000000..e5ad0d7
--- /dev/null
+++ b/tests/hwsim/auth_serv/eap_user_vlan.conf
@@ -0,0 +1,4 @@
+"vlan1"	PAX	0123456789abcdef0123456789abcdef
+radius_accept_attr=64:d:13
+radius_accept_attr=65:d:6
+radius_accept_attr=81:s:2
diff --git a/tests/hwsim/auth_serv/ec-ca-openssl.cnf b/tests/hwsim/auth_serv/ec-ca-openssl.cnf
new file mode 100644
index 0000000..c803dd3
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-ca-openssl.cnf
@@ -0,0 +1,111 @@
+# OpenSSL configuration file for Suite B
+
+HOME			= .
+RANDFILE		= $ENV::HOME/.rnd
+oid_section		= new_oids
+
+[ new_oids ]
+
+[ ca ]
+default_ca	= CA_default
+
+[ CA_default ]
+
+dir		= ./ec-ca
+certs		= $dir/certs
+crl_dir		= $dir/crl
+database	= $dir/index.txt
+#unique_subject	= no
+new_certs_dir	= $dir/newcerts
+certificate	= $dir/cacert.pem
+serial		= $dir/serial
+crlnumber	= $dir/crlnumber
+crl		= $dir/crl.pem
+private_key	= $dir/private/cakey.pem
+RANDFILE	= $dir/private/.rand
+
+x509_extensions	= ext_client
+
+name_opt 	= ca_default
+cert_opt 	= ca_default
+
+copy_extensions = copy
+
+default_days	= 365
+default_crl_days= 30
+default_md	= default
+preserve	= no
+
+policy		= policy_match
+
+[ policy_match ]
+countryName		= match
+stateOrProvinceName	= optional
+organizationName	= match
+organizationalUnitName	= optional
+commonName		= supplied
+#emailAddress		= optional
+
+[ policy_anything ]
+countryName		= optional
+stateOrProvinceName	= optional
+localityName		= optional
+organizationName	= optional
+organizationalUnitName	= optional
+commonName		= supplied
+#emailAddress		= optional
+
+[ req ]
+distinguished_name	= req_distinguished_name
+attributes		= req_attributes
+x509_extensions	= v3_ca
+
+string_mask = utf8only
+
+[ req_distinguished_name ]
+countryName			= Country Name (2 letter code)
+countryName_default		= FI
+countryName_min			= 2
+countryName_max			= 2
+
+localityName			= Locality Name (eg, city)
+localityName_default		= Helsinki
+
+0.organizationName		= Organization Name (eg, company)
+0.organizationName_default	= w1.fi
+
+commonName			= Common Name (e.g. server FQDN or YOUR name)
+#@CN@
+commonName_max			= 64
+
+[ req_attributes ]
+
+[ v3_ca ]
+
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, cRLSign, keyCertSign
+
+[ crl_ext ]
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ ext_client ]
+
+basicConstraints=CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+#@ALTNAME@
+extendedKeyUsage = clientAuth
+keyUsage = digitalSignature, keyEncipherment
+
+[ ext_server ]
+
+basicConstraints=critical, CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+#@ALTNAME@
+extendedKeyUsage = critical, serverAuth
+keyUsage = digitalSignature, keyEncipherment
diff --git a/tests/hwsim/auth_serv/ec-ca.pem b/tests/hwsim/auth_serv/ec-ca.pem
new file mode 100644
index 0000000..a04b886
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-ca.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICAjCCAaegAwIBAgIJANry4MnEh6ybMAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTI1MDEy
+MjExMjk1M1owUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
+VQQKDAV3MS5maTEgMB4GA1UEAwwXU3VpdGUgQiAxMjgtYml0IFJvb3QgQ0EwWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAASqUNEASvF83W/PA2xqq/2fhIgZeLdSnnLc
+0yLcjku5WvpLHGy/pLhRsvghtjWjTsgqBqfeW8tq0ywsUdY0ylsNo2YwZDAdBgNV
+HQ4EFgQU/IP6SzTrGV4cfeWF7Mf8IfXodWgwHwYDVR0jBBgwFoAU/IP6SzTrGV4c
+feWF7Mf8IfXodWgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw
+CgYIKoZIzj0EAwIDSQAwRgIhAIfEWvUO4+28moKfVL8RXbKKexTZk82UCRL2yi01
+c81AAiEAxBGPZU0vnwxjAaCOhRIH+5X9PDkdLSs25S4ua6BicT8=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ec-generate.sh b/tests/hwsim/auth_serv/ec-generate.sh
new file mode 100755
index 0000000..c9fdabc
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-generate.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+OPENSSL=openssl
+
+CURVE=prime256v1
+DIGEST="-sha256"
+DIGEST_CA="-md sha256"
+
+echo
+echo "---[ Root CA ]----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = Suite B 128-bit Root CA/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec-ca.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -x509 -new -key ec-ca.key -out ec-ca.pem -outform PEM -days 3650 $DIGEST
+mkdir -p ec-ca/certs ec-ca/crl ec-ca/newcerts ec-ca/private
+touch ec-ca/index.txt
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Server ]-----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = server.w1.fi/" |
+	sed "s/#@ALTNAME@/subjectAltName=critical,DNS:server.w1.fi/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec-server.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -nodes -key ec-server.key -out ec-server.req -outform PEM $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile ec-ca.key -cert ec-ca.pem -create_serial -in ec-server.req -out ec-server.pem -extensions ext_server $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ User ]-------------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = user/" |
+	sed "s/#@ALTNAME@/subjectAltName=email:user@w1.fi/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec-user.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -nodes -key ec-user.key -out ec-user.req -outform PEM -extensions ext_client $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile ec-ca.key -cert ec-ca.pem -create_serial -in ec-user.req -out ec-user.pem -extensions ext_client $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Verify ]-----------------------------------------------------------"
+echo
+
+$OPENSSL verify -CAfile ec-ca.pem ec-server.pem
+$OPENSSL verify -CAfile ec-ca.pem ec-user.pem
diff --git a/tests/hwsim/auth_serv/ec-server.key b/tests/hwsim/auth_serv/ec-server.key
new file mode 100644
index 0000000..391e9ed
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-server.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIN/qNiKLsQDpQWumSiRRF6LM7TP7GTwdS8vG7xP8vKz/oAoGCCqGSM49
+AwEHoUQDQgAEvl8WCLIK1vIZbxQZ7yDyKzzgvoxlhl+VwbuQNuzcWTq6QJqdEXbH
+gFohTPzAXxlSyHi45Uz6yWrR/uq2OldcmQ==
+-----END EC PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/ec-server.pem b/tests/hwsim/auth_serv/ec-server.pem
new file mode 100644
index 0000000..4222b1e
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-server.pem
@@ -0,0 +1,53 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9573410140069116734 (0x84db95ccdff13b3e)
+    Signature Algorithm: ecdsa-with-SHA256
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 128-bit Root CA
+        Validity
+            Not Before: Jan 25 11:29:53 2015 GMT
+            Not After : Jan 25 11:29:53 2016 GMT
+        Subject: C=FI, O=w1.fi, CN=server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: id-ecPublicKey
+                Public-Key: (256 bit)
+                pub: 
+                    04:be:5f:16:08:b2:0a:d6:f2:19:6f:14:19:ef:20:
+                    f2:2b:3c:e0:be:8c:65:86:5f:95:c1:bb:90:36:ec:
+                    dc:59:3a:ba:40:9a:9d:11:76:c7:80:5a:21:4c:fc:
+                    c0:5f:19:52:c8:78:b8:e5:4c:fa:c9:6a:d1:fe:ea:
+                    b6:3a:57:5c:99
+                ASN1 OID: prime256v1
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                6E:21:26:96:72:29:39:BF:8B:EF:EB:65:CD:E0:4E:97:6F:1A:2C:E5
+            X509v3 Authority Key Identifier: 
+                keyid:FC:83:FA:4B:34:EB:19:5E:1C:7D:E5:85:EC:C7:FC:21:F5:E8:75:68
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: ecdsa-with-SHA256
+         30:44:02:20:47:b1:5e:57:ae:6c:0b:df:78:11:79:5c:b2:60:
+         fd:0c:9c:37:18:19:fe:c1:b6:ca:f6:4f:62:63:13:ff:ff:64:
+         02:20:07:1f:3b:1d:c7:d8:fe:ff:26:0b:68:d0:85:bc:01:15:
+         62:e4:7f:f4:c7:e4:ad:d5:da:40:44:5a:0b:f5:72:9e
+-----BEGIN CERTIFICATE-----
+MIICDzCCAbagAwIBAgIJAITblczf8Ts+MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTE2MDEy
+NTExMjk1M1owNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
+DAxzZXJ2ZXIudzEuZmkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS+XxYIsgrW
+8hlvFBnvIPIrPOC+jGWGX5XBu5A27NxZOrpAmp0RdseAWiFM/MBfGVLIeLjlTPrJ
+atH+6rY6V1yZo4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFG4hJpZyKTm/
+i+/rZc3gTpdvGizlMB8GA1UdIwQYMBaAFPyD+ks06xleHH3lhezH/CH16HVoMBoG
+A1UdEQEB/wQQMA6CDHNlcnZlci53MS5maTAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
+ATALBgNVHQ8EBAMCBaAwCgYIKoZIzj0EAwIDRwAwRAIgR7FeV65sC994EXlcsmD9
+DJw3GBn+wbbK9k9iYxP//2QCIAcfOx3H2P7/Jgto0IW8ARVi5H/0x+St1dpARFoL
+9XKe
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ec-user.key b/tests/hwsim/auth_serv/ec-user.key
new file mode 100644
index 0000000..e390c06
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-user.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIL52ZfaYm8GAzhot94BCQriTmQEq2+JPkS+HCwUpLuwaoAoGCCqGSM49
+AwEHoUQDQgAEnE2sSN8ZOateUoi3Ao0VewSH+1ceTf+NkiJpoymO6U6q0CSlG2bp
+dZyBk+6UIOD9WiCi2tN+QGbvPnPrlLfBOg==
+-----END EC PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/ec-user.pem b/tests/hwsim/auth_serv/ec-user.pem
new file mode 100644
index 0000000..9a6aba8
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec-user.pem
@@ -0,0 +1,52 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9573410140069116735 (0x84db95ccdff13b3f)
+    Signature Algorithm: ecdsa-with-SHA256
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 128-bit Root CA
+        Validity
+            Not Before: Jan 25 11:29:53 2015 GMT
+            Not After : Jan 25 11:29:53 2016 GMT
+        Subject: C=FI, O=w1.fi, CN=user
+        Subject Public Key Info:
+            Public Key Algorithm: id-ecPublicKey
+                Public-Key: (256 bit)
+                pub: 
+                    04:9c:4d:ac:48:df:19:39:ab:5e:52:88:b7:02:8d:
+                    15:7b:04:87:fb:57:1e:4d:ff:8d:92:22:69:a3:29:
+                    8e:e9:4e:aa:d0:24:a5:1b:66:e9:75:9c:81:93:ee:
+                    94:20:e0:fd:5a:20:a2:da:d3:7e:40:66:ef:3e:73:
+                    eb:94:b7:c1:3a
+                ASN1 OID: prime256v1
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                89:28:76:9A:42:DB:B6:F8:36:97:63:8F:7D:0A:EA:0B:FE:66:2B:CD
+            X509v3 Authority Key Identifier: 
+                keyid:FC:83:FA:4B:34:EB:19:5E:1C:7D:E5:85:EC:C7:FC:21:F5:E8:75:68
+
+            X509v3 Subject Alternative Name: 
+                email:user@w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: ecdsa-with-SHA256
+         30:45:02:20:26:84:14:f6:50:ac:ed:da:88:27:6d:18:d5:b3:
+         2c:c8:59:ea:2a:c3:ae:69:03:79:0d:66:5e:5f:a5:52:27:92:
+         02:21:00:db:8d:fd:58:e5:22:9b:17:32:57:34:e9:2e:30:da:
+         1d:77:4c:15:18:9b:7d:e4:5d:bc:64:cd:21:ff:57:df:16
+-----BEGIN CERTIFICATE-----
+MIIB/TCCAaOgAwIBAgIJAITblczf8Ts/MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTE2MDEy
+NTExMjk1M1owLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
+DAR1c2VyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnE2sSN8ZOateUoi3Ao0V
+ewSH+1ceTf+NkiJpoymO6U6q0CSlG2bpdZyBk+6UIOD9WiCi2tN+QGbvPnPrlLfB
+OqOBhzCBhDAJBgNVHRMEAjAAMB0GA1UdDgQWBBSJKHaaQtu2+DaXY499CuoL/mYr
+zTAfBgNVHSMEGDAWgBT8g/pLNOsZXhx95YXsx/wh9eh1aDAVBgNVHREEDjAMgQp1
+c2VyQHcxLmZpMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAsGA1UdDwQEAwIFoDAKBggq
+hkjOPQQDAgNIADBFAiAmhBT2UKzt2ognbRjVsyzIWeoqw65pA3kNZl5fpVInkgIh
+ANuN/VjlIpsXMlc06S4w2h13TBUYm33kXbxkzSH/V98W
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ec2-ca.pem b/tests/hwsim/auth_serv/ec2-ca.pem
new file mode 100644
index 0000000..0054ba8
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICPTCCAcSgAwIBAgIJAL63h7lu0KZpMAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTI1MDEy
+MjExMzIwM1owUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
+VQQKDAV3MS5maTEgMB4GA1UEAwwXU3VpdGUgQiAxOTItYml0IFJvb3QgQ0EwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAAQjdOMC9bqcDR9/SaOhxNbmQLQTGZfhtmoxHkJL
+5GG3bwW5hYA2jYHWU84H+mR6om6fg78G+IxjLly2OWiByYUeWDcsYqLGj3UHHaVv
+rIitaRPyg3dExemnmK3zjgXnoaajZjBkMB0GA1UdDgQWBBSuBbynInvH0vn8IKZc
+MbtBTo9svTAfBgNVHSMEGDAWgBSuBbynInvH0vn8IKZcMbtBTo9svTASBgNVHRMB
+Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBZ
+vEbGRDQNvzAY3nfYrsrE2Dd11smT6zv0mIvDeQCktbISGpStRBQjAaFjcCyjDEkC
+MH7ywcqJe+mpWDt5xFJvB52iZ7rX7rO0OX0qmjI38PC0IOo7euJdfcC1gHdSoAW3
+bA==
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ec2-generate.sh b/tests/hwsim/auth_serv/ec2-generate.sh
new file mode 100755
index 0000000..5a8d2d2
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-generate.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+OPENSSL=openssl
+
+CURVE=secp384r1
+DIGEST="-sha384"
+DIGEST_CA="-md sha384"
+
+echo
+echo "---[ Root CA ]----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = Suite B 192-bit Root CA/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec2-ca.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -x509 -new -key ec2-ca.key -out ec2-ca.pem -outform PEM -days 3650 $DIGEST
+mkdir -p ec-ca/certs ec-ca/crl ec-ca/newcerts ec-ca/private
+touch ec-ca/index.txt
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Server ]-----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = server.w1.fi/" |
+	sed "s/#@ALTNAME@/subjectAltName=critical,DNS:server.w1.fi/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec2-server.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -nodes -key ec2-server.key -out ec2-server.req -outform PEM $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile ec2-ca.key -cert ec2-ca.pem -create_serial -in ec2-server.req -out ec2-server.pem -extensions ext_server $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ User ]-------------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+	sed "s/#@CN@/commonName_default = user/" |
+	sed "s/#@ALTNAME@/subjectAltName=email:user@w1.fi/" \
+	> ec-ca-openssl.cnf.tmp
+$OPENSSL ecparam -out ec2-user.key -name $CURVE -genkey
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -nodes -key ec2-user.key -out ec2-user.req -outform PEM -extensions ext_client $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile ec2-ca.key -cert ec2-ca.pem -create_serial -in ec2-user.req -out ec2-user.pem -extensions ext_client $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Verify ]-----------------------------------------------------------"
+echo
+
+$OPENSSL verify -CAfile ec2-ca.pem ec2-server.pem
+$OPENSSL verify -CAfile ec2-ca.pem ec2-user.pem
diff --git a/tests/hwsim/auth_serv/ec2-server.key b/tests/hwsim/auth_serv/ec2-server.key
new file mode 100644
index 0000000..9cd76ee
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-server.key
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCjaz/zVDXqNO/XprtliomKOC6QjbBFgsF2YwUAtKB5ukL4miVGNyCu
+jIlq9eUD1x6gBwYFK4EEACKhZANiAARWq1ut1b6ctOFBkEOjULL3VjJFP15g0gk+
+sBTMBogU5WRN7Qod/jfem5k4O7FKYZNAarDFMh2yDMXZvRooiNyL0AH2wk0qzN5u
+n02JOt9Q76TVYflE91C5DTxjgLOgxBw=
+-----END EC PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/ec2-server.pem b/tests/hwsim/auth_serv/ec2-server.pem
new file mode 100644
index 0000000..a7cc37e
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-server.pem
@@ -0,0 +1,58 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9347590364512421238 (0x81b94fe92ea08576)
+    Signature Algorithm: ecdsa-with-SHA384
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 192-bit Root CA
+        Validity
+            Not Before: Jan 25 11:32:03 2015 GMT
+            Not After : Jan 25 11:32:03 2016 GMT
+        Subject: C=FI, O=w1.fi, CN=server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: id-ecPublicKey
+                Public-Key: (384 bit)
+                pub: 
+                    04:56:ab:5b:ad:d5:be:9c:b4:e1:41:90:43:a3:50:
+                    b2:f7:56:32:45:3f:5e:60:d2:09:3e:b0:14:cc:06:
+                    88:14:e5:64:4d:ed:0a:1d:fe:37:de:9b:99:38:3b:
+                    b1:4a:61:93:40:6a:b0:c5:32:1d:b2:0c:c5:d9:bd:
+                    1a:28:88:dc:8b:d0:01:f6:c2:4d:2a:cc:de:6e:9f:
+                    4d:89:3a:df:50:ef:a4:d5:61:f9:44:f7:50:b9:0d:
+                    3c:63:80:b3:a0:c4:1c
+                ASN1 OID: secp384r1
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                19:D7:57:D0:3B:91:84:A4:AF:93:03:32:3C:AB:C4:F9:A7:B0:27:19
+            X509v3 Authority Key Identifier: 
+                keyid:AE:05:BC:A7:22:7B:C7:D2:F9:FC:20:A6:5C:31:BB:41:4E:8F:6C:BD
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: ecdsa-with-SHA384
+         30:65:02:30:79:68:37:af:eb:46:e8:77:35:13:77:d5:db:eb:
+         f9:75:40:cd:d4:3d:0a:03:ec:67:a0:22:fe:65:f5:d7:ca:53:
+         4a:85:f5:14:4b:41:f9:b9:98:a6:85:8b:ac:e0:c8:6c:02:31:
+         00:83:12:02:be:93:2b:c2:00:74:ec:cb:fc:5a:8c:a6:5e:52:
+         ee:20:76:3d:73:2b:fb:fe:60:4c:52:f3:bc:1e:4c:e8:f9:ea:
+         f6:e2:f6:ca:c6:a8:3b:2d:9a:17:eb:4d:0a
+-----BEGIN CERTIFICATE-----
+MIICTTCCAdOgAwIBAgIJAIG5T+kuoIV2MAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTE2MDEy
+NTExMzIwM1owNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
+DAxzZXJ2ZXIudzEuZmkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARWq1ut1b6ctOFB
+kEOjULL3VjJFP15g0gk+sBTMBogU5WRN7Qod/jfem5k4O7FKYZNAarDFMh2yDMXZ
+vRooiNyL0AH2wk0qzN5un02JOt9Q76TVYflE91C5DTxjgLOgxByjgZIwgY8wDAYD
+VR0TAQH/BAIwADAdBgNVHQ4EFgQUGddX0DuRhKSvkwMyPKvE+aewJxkwHwYDVR0j
+BBgwFoAUrgW8pyJ7x9L5/CCmXDG7QU6PbL0wGgYDVR0RAQH/BBAwDoIMc2VydmVy
+LncxLmZpMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDAKBggq
+hkjOPQQDAwNoADBlAjB5aDev60bodzUTd9Xb6/l1QM3UPQoD7GegIv5l9dfKU0qF
+9RRLQfm5mKaFi6zgyGwCMQCDEgK+kyvCAHTsy/xajKZeUu4gdj1zK/v+YExS87we
+TOj56vbi9srGqDstmhfrTQo=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ec2-user.key b/tests/hwsim/auth_serv/ec2-user.key
new file mode 100644
index 0000000..adfa937
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-user.key
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDB7tpaHBuZZG+MVYjRVpZvZvZxxFOu/reH2Ms3DiBH5DHW7dLP7T4Gs
+X+yw8bQZwCqgBwYFK4EEACKhZANiAATJYVk5woo/LAFd+znRAoMOClGXtfO2yZlp
+3n6jYUsG48W03XOlYd2/aCJVtGp6SwRVxumfYT4TejEj/Ky44vOlmQ9pasNfMYYN
+kpHcAWJ8sV7mP7LM9YVksksfhon91+E=
+-----END EC PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/ec2-user.pem b/tests/hwsim/auth_serv/ec2-user.pem
new file mode 100644
index 0000000..ef86cd1
--- /dev/null
+++ b/tests/hwsim/auth_serv/ec2-user.pem
@@ -0,0 +1,57 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9347590364512421239 (0x81b94fe92ea08577)
+    Signature Algorithm: ecdsa-with-SHA384
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 192-bit Root CA
+        Validity
+            Not Before: Jan 25 11:32:03 2015 GMT
+            Not After : Jan 25 11:32:03 2016 GMT
+        Subject: C=FI, O=w1.fi, CN=user
+        Subject Public Key Info:
+            Public Key Algorithm: id-ecPublicKey
+                Public-Key: (384 bit)
+                pub: 
+                    04:c9:61:59:39:c2:8a:3f:2c:01:5d:fb:39:d1:02:
+                    83:0e:0a:51:97:b5:f3:b6:c9:99:69:de:7e:a3:61:
+                    4b:06:e3:c5:b4:dd:73:a5:61:dd:bf:68:22:55:b4:
+                    6a:7a:4b:04:55:c6:e9:9f:61:3e:13:7a:31:23:fc:
+                    ac:b8:e2:f3:a5:99:0f:69:6a:c3:5f:31:86:0d:92:
+                    91:dc:01:62:7c:b1:5e:e6:3f:b2:cc:f5:85:64:b2:
+                    4b:1f:86:89:fd:d7:e1
+                ASN1 OID: secp384r1
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                75:EA:7B:CE:8A:99:D2:E7:77:B4:3B:80:68:59:E9:B6:88:B2:FA:F6
+            X509v3 Authority Key Identifier: 
+                keyid:AE:05:BC:A7:22:7B:C7:D2:F9:FC:20:A6:5C:31:BB:41:4E:8F:6C:BD
+
+            X509v3 Subject Alternative Name: 
+                email:user@w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: ecdsa-with-SHA384
+         30:65:02:31:00:c2:b7:35:4e:5e:d1:da:7f:35:a0:ac:54:92:
+         18:08:0d:9c:86:e9:4e:cf:3a:09:48:23:eb:4d:56:77:e5:d0:
+         e7:b0:55:b3:0e:91:2d:f8:3e:1c:4e:0d:b7:32:dc:11:1b:02:
+         30:49:c2:6b:63:39:3c:4b:d9:e9:8d:b9:ce:6e:8e:9f:88:43:
+         03:e0:5f:7e:75:44:12:66:f8:c6:ae:8e:f1:da:10:02:36:8c:
+         7b:a2:89:a0:05:3b:c6:39:d6:e1:7a:b7:85
+-----BEGIN CERTIFICATE-----
+MIICOjCCAcCgAwIBAgIJAIG5T+kuoIV3MAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTE2MDEy
+NTExMzIwM1owLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
+DAR1c2VyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyWFZOcKKPywBXfs50QKDDgpR
+l7XztsmZad5+o2FLBuPFtN1zpWHdv2giVbRqeksEVcbpn2E+E3oxI/ysuOLzpZkP
+aWrDXzGGDZKR3AFifLFe5j+yzPWFZLJLH4aJ/dfho4GHMIGEMAkGA1UdEwQCMAAw
+HQYDVR0OBBYEFHXqe86KmdLnd7Q7gGhZ6baIsvr2MB8GA1UdIwQYMBaAFK4FvKci
+e8fS+fwgplwxu0FOj2y9MBUGA1UdEQQOMAyBCnVzZXJAdzEuZmkwEwYDVR0lBAww
+CgYIKwYBBQUHAwIwCwYDVR0PBAQDAgWgMAoGCCqGSM49BAMDA2gAMGUCMQDCtzVO
+XtHafzWgrFSSGAgNnIbpTs86CUgj601Wd+XQ57BVsw6RLfg+HE4NtzLcERsCMEnC
+a2M5PEvZ6Y25zm6On4hDA+BffnVEEmb4xq6O8doQAjaMe6KJoAU7xjnW4Xq3hQ==
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/index-revoked.txt b/tests/hwsim/auth_serv/index-revoked.txt
new file mode 100644
index 0000000..95b052e
--- /dev/null
+++ b/tests/hwsim/auth_serv/index-revoked.txt
@@ -0,0 +1,8 @@
+V	230627164122Z		D8D3E3A6CBE3CCC1	unknown	/C=FI/O=w1.fi/CN=Root CA
+V	150215075930Z		D8D3E3A6CBE3CCC9	unknown	/C=FI/O=w1.fi/CN=server3.w1.fi
+V	140102000000Z		D8D3E3A6CBE3CCCA	unknown	/C=FI/O=w1.fi/CN=server4.w1.fi
+V	150215083008Z		D8D3E3A6CBE3CCCB	unknown	/C=FI/O=w1.fi/CN=server5.w1.fi
+V	150228224144Z		D8D3E3A6CBE3CCCC	unknown	/C=FI/O=w1.fi/CN=server6.w1.fi
+V	160111185024Z		D8D3E3A6CBE3CCCD	unknown	/C=FI/O=w1.fi/CN=ocsp.w1.fi
+R	150929211122Z	160111185024Z	D8D3E3A6CBE3CCD0	unknown	/C=FI/O=w1.fi/CN=server.w1.fi
+R	150929211300Z	160111185024Z	D8D3E3A6CBE3CCD1	unknown	/C=FI/O=w1.fi/CN=Test User
diff --git a/tests/hwsim/auth_serv/index-unknown.txt b/tests/hwsim/auth_serv/index-unknown.txt
new file mode 100644
index 0000000..97dfbba
--- /dev/null
+++ b/tests/hwsim/auth_serv/index-unknown.txt
@@ -0,0 +1 @@
+V	230627164122Z		D8D3E3A6CBE3CCC1	unknown	/C=FI/O=w1.fi/CN=Root CA
diff --git a/tests/hwsim/auth_serv/index.txt b/tests/hwsim/auth_serv/index.txt
new file mode 100644
index 0000000..52c8e0c
--- /dev/null
+++ b/tests/hwsim/auth_serv/index.txt
@@ -0,0 +1,8 @@
+V	230627164122Z		D8D3E3A6CBE3CCC1	unknown	/C=FI/O=w1.fi/CN=Root CA
+V	150215075930Z		D8D3E3A6CBE3CCC9	unknown	/C=FI/O=w1.fi/CN=server3.w1.fi
+V	140102000000Z		D8D3E3A6CBE3CCCA	unknown	/C=FI/O=w1.fi/CN=server4.w1.fi
+V	150215083008Z		D8D3E3A6CBE3CCCB	unknown	/C=FI/O=w1.fi/CN=server5.w1.fi
+V	150228224144Z		D8D3E3A6CBE3CCCC	unknown	/C=FI/O=w1.fi/CN=server6.w1.fi
+V	160111185024Z		D8D3E3A6CBE3CCCD	unknown	/C=FI/O=w1.fi/CN=ocsp.w1.fi
+V	150929211122Z		D8D3E3A6CBE3CCD0	unknown	/C=FI/O=w1.fi/CN=server.w1.fi
+V	150929211300Z		D8D3E3A6CBE3CCD1	unknown	/C=FI/O=w1.fi/CN=Test User
diff --git a/tests/hwsim/auth_serv/ocsp-req.der b/tests/hwsim/auth_serv/ocsp-req.der
new file mode 100644
index 0000000..20999b9
--- /dev/null
+++ b/tests/hwsim/auth_serv/ocsp-req.der
Binary files differ
diff --git a/tests/hwsim/auth_serv/ocsp-responder.key b/tests/hwsim/auth_serv/ocsp-responder.key
new file mode 100644
index 0000000..fb866fb
--- /dev/null
+++ b/tests/hwsim/auth_serv/ocsp-responder.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJeLx3nLPZsq7AW
+nvoSL7JMyCN7aAh2OIOX9T8FrF3ZganOdZKhvJbGyADuHtfw2orY58DXQsMlYufH
+YPqogkwbznOaq42z/j22fwH+WWRCdagEGActImQnufGvAbTtv6bqkXjRnDD1YTf/
++Rv4Fl9rdzL51+OdDNXDuUMW8DrDAgMBAAECgYAja1yD3aIqFQ5K21MaaX4bM/AS
+S7Eu7Prv9r72ktPVlxmOdLcYNRHUBwk0VhS94NAk/kmXG6fgRI5NZGQ3ojqtOXLV
+VhlcitYAfJvNpyKmFKgdGZQIxaaQr/F2X8tH5yFdIt+6mDOGptTb/S3ljQwNsg59
+7t/jYzSe5mK/Gbw4MQJBAN3sZqGz6ABygLTuTiXhE9sCXDSGy4d8ZWMaajuD7N6k
+sAGKsaiVozeIvg0JNiCMm02A8M/cWjGedDWFxrnvvF8CQQDNwagUpozfXMboibHI
+BNwpUzyri/5bqJ/dU7/sAOA1AZ9yoO5s2WlNutXkG3mDoQCzseG/pNxU403dU0jQ
+wpwdAkEAk5lbWUkSkNmXCL9GcqMUVaFoOfc8/suZkyRKa3L+48Wc2imop3t+przn
+yjvKKDPcRtvvThA8XKwKll53Ict0+QJBAKj7o09Sed/4EmRosdnUI/zMn8dD8mLU
+2narkbQCBCGEc69w/F/pLtLn30K4TdQNJsZuETmT7GDLTee3vtW0/wECQCtyVgw/
+aZ0QTac8ut1oG072qOA2cFGhEuDELlX8JcNy28ygmzn0KS8uiTsq6YVu8V7WCj4X
+EkAZMm19nY5ZE+A=
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/ocsp-responder.pem b/tests/hwsim/auth_serv/ocsp-responder.pem
new file mode 100644
index 0000000..bbde1e8
--- /dev/null
+++ b/tests/hwsim/auth_serv/ocsp-responder.pem
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162829 (0xd8d3e3a6cbe3cccd)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Jan 11 18:50:24 2015 GMT
+            Not After : Jan 11 18:50:24 2016 GMT
+        Subject: C=FI, O=w1.fi, CN=ocsp.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:b2:5e:2f:1d:e7:2c:f6:6c:ab:b0:16:9e:fa:12:
+                    2f:b2:4c:c8:23:7b:68:08:76:38:83:97:f5:3f:05:
+                    ac:5d:d9:81:a9:ce:75:92:a1:bc:96:c6:c8:00:ee:
+                    1e:d7:f0:da:8a:d8:e7:c0:d7:42:c3:25:62:e7:c7:
+                    60:fa:a8:82:4c:1b:ce:73:9a:ab:8d:b3:fe:3d:b6:
+                    7f:01:fe:59:64:42:75:a8:04:18:07:2d:22:64:27:
+                    b9:f1:af:01:b4:ed:bf:a6:ea:91:78:d1:9c:30:f5:
+                    61:37:ff:f9:1b:f8:16:5f:6b:77:32:f9:d7:e3:9d:
+                    0c:d5:c3:b9:43:16:f0:3a:c3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature, Non Repudiation, Key Encipherment
+            X509v3 Extended Key Usage: 
+                OCSP Signing
+    Signature Algorithm: sha256WithRSAEncryption
+         41:42:b6:70:4a:70:1f:ad:d9:25:f7:02:94:bd:91:b7:69:ad:
+         31:59:c6:2a:4e:5e:4a:ed:5d:c1:24:09:98:94:15:42:86:2c:
+         b2:9d:62:7a:e0:ec:60:39:47:93:c9:c7:61:01:b5:2c:00:53:
+         86:6e:66:99:ee:b3:57:5d:fb:83:6b:d3:77:26:0c:c7:2d:16:
+         ea:84:69:59:b7:a8:de:35:61:0b:7a:f3:62:1e:1a:94:91:c4:
+         bd:85:4a:63:10:09:11:88:75:c9:f5:57:84:9a:ef:d1:78:29:
+         5e:76:fc:33:76:84:b2:b5:f6:88:cc:fb:f9:cf:9f:b4:88:29:
+         3c:9d
+-----BEGIN CERTIFICATE-----
+MIICDjCCAXegAwIBAgIJANjT46bL48zNMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAx
+MTExODUwMjRaFw0xNjAxMTExODUwMjRaMDIxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTETMBEGA1UEAwwKb2NzcC53MS5maTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEAsl4vHecs9myrsBae+hIvskzII3toCHY4g5f1PwWsXdmBqc51kqG8
+lsbIAO4e1/DaitjnwNdCwyVi58dg+qiCTBvOc5qrjbP+PbZ/Af5ZZEJ1qAQYBy0i
+ZCe58a8BtO2/puqReNGcMPVhN//5G/gWX2t3MvnX450M1cO5QxbwOsMCAwEAAaMv
+MC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw
+DQYJKoZIhvcNAQELBQADgYEAQUK2cEpwH63ZJfcClL2Rt2mtMVnGKk5eSu1dwSQJ
+mJQVQoYssp1ieuDsYDlHk8nHYQG1LABThm5mme6zV137g2vTdyYMxy0W6oRpWbeo
+3jVhC3rzYh4alJHEvYVKYxAJEYh1yfVXhJrv0XgpXnb8M3aEsrX2iMz7+c+ftIgp
+PJ0=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-eku-client-server.pem b/tests/hwsim/auth_serv/server-eku-client-server.pem
index 4f94455..7ed4014 100644
--- a/tests/hwsim/auth_serv/server-eku-client-server.pem
+++ b/tests/hwsim/auth_serv/server-eku-client-server.pem
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162828 (0xd8d3e3a6cbe3cccc)
+        Serial Number: 15624081837803162841 (0xd8d3e3a6cbe3ccd9)
     Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 28 22:41:44 2014 GMT
-            Not After : Feb 28 22:41:44 2015 GMT
+            Not Before: Feb 19 12:18:22 2015 GMT
+            Not After : Feb 19 12:18:22 2016 GMT
         Subject: C=FI, O=w1.fi, CN=server6.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -36,18 +36,18 @@
             X509v3 Extended Key Usage: 
                 TLS Web Client Authentication, TLS Web Server Authentication
     Signature Algorithm: sha1WithRSAEncryption
-         64:52:09:25:e9:ce:db:1f:fa:81:aa:8a:ed:7e:f7:db:1e:27:
-         de:a7:41:b3:ab:73:e3:bc:b7:24:ed:5f:a6:88:5b:c8:16:1a:
-         f9:60:93:0b:d2:3f:5f:ce:3c:8c:50:53:8e:30:ae:0a:f8:0a:
-         53:74:d7:37:47:55:81:7d:75:c7:a2:e2:ff:82:bd:55:67:3d:
-         dd:e3:ca:d6:ef:33:63:2d:f4:65:4f:a2:8c:d5:f1:ac:af:ce:
-         02:83:91:37:cc:7c:55:7a:81:9c:c9:46:9e:9c:e6:ce:d5:35:
-         6c:f7:2e:08:05:c3:ca:c7:25:8c:e0:ba:4e:4c:fc:d3:a2:5a:
-         57:0e
+         b8:35:8c:b6:18:ac:e9:f6:cb:2c:df:d8:50:88:48:50:33:50:
+         fa:92:21:94:b7:82:04:0c:c2:c4:16:bc:dd:2f:75:f8:9d:1a:
+         d5:1a:50:dc:7c:97:78:10:25:33:ba:01:6d:47:b8:28:4f:7c:
+         d8:c4:a6:85:0d:f5:84:5f:31:68:1e:44:13:16:fd:ce:8b:98:
+         39:46:03:de:aa:62:16:ee:ae:aa:15:27:4a:f2:9d:9c:1f:5a:
+         61:04:ef:3a:7b:c4:5a:3d:a1:d0:2e:f6:31:ea:92:7e:5f:6b:
+         4d:d3:06:d2:ee:a9:4a:56:68:38:76:25:58:e0:07:fb:d5:d8:
+         fa:b0
 -----BEGIN CERTIFICATE-----
-MIIChzCCAfCgAwIBAgIJANjT46bL48zMMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNDAy
-MjgyMjQxNDRaFw0xNTAyMjgyMjQxNDRaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIChzCCAfCgAwIBAgIJANjT46bL48zZMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
+MTkxMjE4MjJaFw0xNjAyMTkxMjE4MjJaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNi53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEAyjAe/RNqAihRmg6pHnJ+51rIywx+ipmBjQWzCbCphueuRPrg
 x+7zGLQxZeMFb2ZO4+SFgZtHf1+1FiuwWZGcxVXT08osgc7wJ6hU3g5P2PARvQsQ
@@ -55,8 +55,8 @@
 AaOBpDCBoTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTHxu/1YdKgCIFqa0Qs9XL32t5b
 uTAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wHQYDVR0l
-BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4GBAGRSCSXp
-ztsf+oGqiu1+99seJ96nQbOrc+O8tyTtX6aIW8gWGvlgkwvSP1/OPIxQU44wrgr4
-ClN01zdHVYF9dcei4v+CvVVnPd3jytbvM2Mt9GVPoozV8ayvzgKDkTfMfFV6gZzJ
-Rp6c5s7VNWz3LggFw8rHJYzguk5M/NOiWlcO
+BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4GBALg1jLYY
+rOn2yyzf2FCISFAzUPqSIZS3ggQMwsQWvN0vdfidGtUaUNx8l3gQJTO6AW1HuChP
+fNjEpoUN9YRfMWgeRBMW/c6LmDlGA96qYhburqoVJ0rynZwfWmEE7zp7xFo9odAu
+9jHqkn5fa03TBtLuqUpWaDh2JVjgB/vV2Pqw
 -----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-eku-client.pem b/tests/hwsim/auth_serv/server-eku-client.pem
index a924042..cbb8437 100644
--- a/tests/hwsim/auth_serv/server-eku-client.pem
+++ b/tests/hwsim/auth_serv/server-eku-client.pem
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162827 (0xd8d3e3a6cbe3cccb)
+        Serial Number: 15624081837803162840 (0xd8d3e3a6cbe3ccd8)
     Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 15 08:30:08 2014 GMT
-            Not After : Feb 15 08:30:08 2015 GMT
+            Not Before: Feb 19 12:18:03 2015 GMT
+            Not After : Feb 19 12:18:03 2016 GMT
         Subject: C=FI, O=w1.fi, CN=server5.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -36,18 +36,18 @@
             X509v3 Extended Key Usage: 
                 TLS Web Client Authentication
     Signature Algorithm: sha1WithRSAEncryption
-         6f:2d:cb:3b:91:50:15:e1:c7:41:15:6c:a4:89:e5:0e:f9:f9:
-         9b:10:36:d8:67:a8:29:e2:6a:6f:89:7b:66:bd:f1:b8:fa:1c:
-         f7:22:8b:85:4e:37:f3:d6:1e:35:df:c7:04:e6:13:20:ca:fa:
-         62:cc:8d:3a:bd:97:10:5c:1b:0b:39:79:ac:13:61:59:79:fd:
-         a1:4b:7d:c9:c5:c4:19:4d:76:5b:cd:6d:1e:f2:aa:ef:67:51:
-         aa:0c:ef:6a:f2:10:71:6f:19:e6:12:ab:3e:65:76:0f:5a:0f:
-         cf:96:30:c3:fc:59:e9:13:af:e1:8a:b0:2c:78:ad:3d:b4:e9:
-         e5:20
+         49:88:dd:04:23:86:22:49:cb:73:57:9a:f7:d8:71:cf:33:62:
+         cc:24:a8:e9:ae:cd:22:91:16:2f:17:86:fc:09:8f:79:c0:93:
+         22:e6:77:25:21:8c:45:38:a3:4d:07:6e:d0:c3:ca:49:8a:3e:
+         86:1f:4e:dd:72:93:f3:47:7d:c3:5b:95:f1:98:50:a5:4e:36:
+         ed:71:94:3a:55:ee:ae:21:e3:27:3d:90:df:4a:be:f5:93:a5:
+         e2:0b:1a:3d:7d:c7:02:98:c1:17:67:9e:9b:a2:1d:65:fc:81:
+         59:72:2b:89:a9:47:31:ad:30:c0:82:39:47:a2:d2:eb:0e:71:
+         d6:3c
 -----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL48zLMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNDAy
-MTUwODMwMDhaFw0xNTAyMTUwODMwMDhaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL48zYMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
+MTkxMjE4MDNaFw0xNjAyMTkxMjE4MDNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNS53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEAo5np4uEXYDtwNBp0XEbjuL27qsnz7vsSMKBpw3Q4gDq6I1LH
 wWrPut1B49JpNaSmYGwxH4W9Vmx7CWPNp1FrhECQd36XaHs4tcQVO3Q3NCi6euLX
@@ -55,8 +55,8 @@
 AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQzFp07FxWCKzRuOOjMIr9Jp14q
 KzAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAby3LO5FQFeHHQRVspInl
-Dvn5mxA22GeoKeJqb4l7Zr3xuPoc9yKLhU4389YeNd/HBOYTIMr6YsyNOr2XEFwb
-Czl5rBNhWXn9oUt9ycXEGU12W81tHvKq72dRqgzvavIQcW8Z5hKrPmV2D1oPz5Yw
-w/xZ6ROv4YqwLHitPbTp5SA=
+BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEASYjdBCOGIknLc1ea99hx
+zzNizCSo6a7NIpEWLxeG/AmPecCTIuZ3JSGMRTijTQdu0MPKSYo+hh9O3XKT80d9
+w1uV8ZhQpU427XGUOlXuriHjJz2Q30q+9ZOl4gsaPX3HApjBF2eem6IdZfyBWXIr
+ialHMa0wwII5R6LS6w5x1jw=
 -----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-no-dnsname.pem b/tests/hwsim/auth_serv/server-no-dnsname.pem
index 1c745c5..93d0ec2 100644
--- a/tests/hwsim/auth_serv/server-no-dnsname.pem
+++ b/tests/hwsim/auth_serv/server-no-dnsname.pem
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162825 (0xd8d3e3a6cbe3ccc9)
+        Serial Number: 15624081837803162838 (0xd8d3e3a6cbe3ccd6)
     Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 15 07:59:30 2014 GMT
-            Not After : Feb 15 07:59:30 2015 GMT
+            Not Before: Feb 19 12:16:15 2015 GMT
+            Not After : Feb 19 12:16:15 2016 GMT
         Subject: C=FI, O=w1.fi, CN=server3.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -36,18 +36,18 @@
             X509v3 Extended Key Usage: 
                 TLS Web Server Authentication
     Signature Algorithm: sha1WithRSAEncryption
-         64:1e:41:7e:12:b1:d2:2d:fb:da:11:29:77:a4:99:13:6a:ff:
-         57:66:4f:30:fe:64:0e:b2:a1:5a:1a:55:37:4e:e1:1d:87:94:
-         b4:5d:9a:2e:2b:01:97:c6:22:b8:74:4b:58:22:83:db:c6:3e:
-         77:b7:73:5b:3b:83:a0:23:a3:c6:1f:33:6c:cf:b5:d6:36:89:
-         fc:ad:92:49:fd:ee:fb:8e:69:6c:84:18:0d:cc:39:01:21:35:
-         f6:46:77:8c:61:f7:18:1c:f6:da:0e:4d:90:69:ca:bd:e6:8d:
-         9b:e8:e6:b6:93:56:24:2d:da:59:0b:cd:cb:68:96:53:a3:16:
-         1f:ae
+         91:6b:2b:90:41:55:93:9a:70:d9:56:57:21:56:08:6e:fb:04:
+         e3:40:0d:eb:25:b5:56:21:7d:7b:81:12:97:22:e8:38:95:bc:
+         ba:cb:db:97:a8:6f:dd:da:61:40:dd:fc:0d:82:e6:a0:b5:b0:
+         13:d9:dc:ee:84:d7:27:f2:b3:be:01:31:11:5b:23:29:6d:37:
+         8b:24:3c:d9:6c:21:7c:cc:d6:a2:68:32:39:40:00:5f:04:af:
+         db:32:f7:10:af:e8:53:c4:d3:2f:03:61:cb:fa:67:c5:18:20:
+         63:f9:d9:42:01:34:c9:eb:9d:33:c8:a3:7e:b5:fb:fe:6b:5f:
+         f8:86
 -----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL48zJMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNDAy
-MTUwNzU5MzBaFw0xNTAyMTUwNzU5MzBaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL48zWMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
+MTkxMjE2MTVaFw0xNjAyMTkxMjE2MTVaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyMy53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEA2/wPoUiHaIbEnnr4GCh3baNYD9u+a9RDQ8S6FzebqP+WonMU
 ExyuGQ+BVDUQZJTjZGW+mwsW0p6SmHeH4pqZ/B1XDIoNTCEvrmfXY2HrkVtYL61n
@@ -55,8 +55,8 @@
 AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBSOmk9NRq1ZrH9MnL5tW9eZY43H
 cDAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAZB5BfhKx0i372hEpd6SZ
-E2r/V2ZPMP5kDrKhWhpVN07hHYeUtF2aLisBl8YiuHRLWCKD28Y+d7dzWzuDoCOj
-xh8zbM+11jaJ/K2SSf3u+45pbIQYDcw5ASE19kZ3jGH3GBz22g5NkGnKveaNm+jm
-tpNWJC3aWQvNy2iWU6MWH64=
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAkWsrkEFVk5pw2VZXIVYI
+bvsE40AN6yW1ViF9e4ESlyLoOJW8usvbl6hv3dphQN38DYLmoLWwE9nc7oTXJ/Kz
+vgExEVsjKW03iyQ82WwhfMzWomgyOUAAXwSv2zL3EK/oU8TTLwNhy/pnxRggY/nZ
+QgE0yeudM8ijfrX7/mtf+IY=
 -----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/user.rsa-key b/tests/hwsim/auth_serv/user.rsa-key
new file mode 100644
index 0000000..4c3cfbf
--- /dev/null
+++ b/tests/hwsim/auth_serv/user.rsa-key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQCmli6bIozflL6LiUn2eHaiYH4UlfOW/qsZJQM0ZHQBPqiffPFH
+YWBMgpIofCugDsuHv1nr1/NhIjsU86sx9lqVH7h6uCw8qWFTeJvoPlDswtZE50PN
+vD5O50b+kp7DmA8pWMjLiQF1R+mVVw92xS8FXsceDfI8EmNduVQZr39AawIDAQAB
+AoGBAJBKEtJCidx6nNSFtK+sRa19gJdaDqQhr5dW7MCrpaMSX8HM2bvnBx8eFXTF
+oI/BYN8SidNyuBbRLHWIXScoZ+nOhmLChexxxqNlgOtVR8YKkQfwmcwC8tiUf968
+xJb61UOWVYdeQ4qTacH8D/W1uj/fQKJj0FZ2d6dR4FOViuvJAkEA1x2xVGF9yPUm
+JUeCYT8uaL9kPFh7uKfa1lxgTu+bku39xWQmxlCymRDrIlRW5aMlHabyyHe8L29+
+N2tRADpwvQJBAMY/VKrCjAHZV0w60/TXEJiSlreevIBFeP+OX46U823Z3RDrQjMF
+gVhL/0soloFncD3gVYkRhMj65C1f0rXnrEcCQQCHzekLmlisq4efdVusRRTpcBq5
+tiq1UtLnDX6HluEiizjwit+nx35Y/8NR8ujBJJPj+me/g0e8sqh+GDQU7tAJAkAO
+7mYqFk0FNqFklGmyXyBY3XGMkuAPqSvb05VO39kVxPrpc06hGSEMzWyE9KGhTXEe
+t+65TCB8Iqlc4YK1QKWxAkEAyuUKlxOmdlR0zRJwpIvWL5IIz4S8UooUDA0mkdBD
+ZK3tDnLRVLn28Mx+wxIc1egkNVMPvQLuQDhc3G9bXxnMzw==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/hwsim/dictionary.radius b/tests/hwsim/dictionary.radius
index aca3a6e..b7f521e 100644
--- a/tests/hwsim/dictionary.radius
+++ b/tests/hwsim/dictionary.radius
@@ -1,9 +1,11 @@
 ATTRIBUTE	User-Name		1	string
 ATTRIBUTE	User-Password		2	string
 ATTRIBUTE	NAS-IP-Address		4	ipaddr
+ATTRIBUTE	State			24	octets
 ATTRIBUTE	Calling-Station-Id	31	string
 ATTRIBUTE	NAS-Identifier		32	string
 ATTRIBUTE	Acct-Session-Id		44	string
+ATTRIBUTE	Acct-Multi-Session-Id	50	string
 ATTRIBUTE	Event-Timestamp		55	date
 ATTRIBUTE	Tunnel-Password		69	octets
 ATTRIBUTE	EAP-Message		79	string
diff --git a/tests/hwsim/example-setup.txt b/tests/hwsim/example-setup.txt
new file mode 100644
index 0000000..2396b97
--- /dev/null
+++ b/tests/hwsim/example-setup.txt
@@ -0,0 +1,177 @@
+Step-by-step guide for setting up hostapd/wpa_supplicant test framework
+-----------------------------------------------------------------------
+
+This document can be used as a quick guide for getting started with
+hostapd/wpa_supplicant test framework with mac80211_hwsim. While the
+example here uses Ubuntu 14.04.1 server to have a list of exact steps,
+there are no requirements for using that specific distribution in the
+testing setup.
+
+The steps here describe how to run a full Linux installation in a
+virtual machine with any host system (e.g., Linux, Windows, or OS X as
+the host and using kvm, VirtualBox, etc. for running the virtual guest
+system). For more advanced (and significantly faster and with more
+testing coverage) configuration on a Linux host system, parallel virtual
+machines can be used as an alternative setup. See tests/hwsim/vm/README
+for more details on that.
+
+
+Install Ubuntu Server 14.04.1 in the virtual machine
+
+- download installation image, e.g.,
+  http://releases.ubuntu.com/14.04.1/ubuntu-14.04.1-server-amd64.iso
+- use virtualization software specific steps to create a new VM and
+  install the the guest system with default settings (i.e., no need to
+  select any extra packages during initial installation)
+- if the host system has multiple CPU cores, it is likely a good idea to
+  enabled at least two CPUs in the guest; 1024 MB of RAM should be enough
+  for testing purposes
+- 8 GB of virtual hard driver should be fine for this purpose
+- boot to the installed operating system
+
+
+Install the prerequisite packages that may not have been installed by default
+
+sudo apt-get install build-essential git libpcap-dev libsqlite3-dev binutils-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libssl-dev libiberty-dev libdbus-1-dev iw bridge-utils python-pyrad python-crypto
+
+
+Install a recent kernel wireless components (mac80211_hwsim, mac80211,
+cfg80211)
+
+For this step, the kernel version may be updated, but the simpler option
+is to install the latest version of Backports package. For example:
+
+wget http://www.kernel.org/pub/linux/kernel/projects/backports/stable/v3.19-rc1/backports-3.19-rc1-1.tar.xz
+tar xJf backports-3.19-rc1-1.tar.xz
+cd backports-3.19-rc1-1
+
+cat > defconfigs/mac80211_hwsim <<EOF
+CPTCFG_CFG80211=m
+CPTCFG_CFG80211_WEXT=y
+CPTCFG_MAC80211=m
+CPTCFG_MAC80211_LEDS=y
+CPTCFG_MAC80211_MESH=y
+CPTCFG_WLAN=y
+CPTCFG_MAC80211_HWSIM=m
+EOF
+
+make defconfig-mac80211_hwsim
+make
+sudo make install
+cd ..
+
+
+Update iw based on custom iw.git build
+
+Couple of the test cases expect iw to have support for requesting
+cfg80211 scan results to be flushed. That functionality is not included
+in the version that Ubuntu 14.04.1 includes (iw v3.4). Following steps
+can be used to replace that version with a custom build. This is
+optional, i.e., most test cases will work with the old iw version, but
+some test cases are skipped and some are more likely to fail if iw does
+not get updated.
+
+wget https://www.kernel.org/pub/software/network/iw/iw-3.17.tar.gz
+tar xf iw-3.17.tar.gz
+cd iw-3.17
+make
+sudo mv /sbin/iw{,-distro}
+sudo cp iw /sbin/iw
+cd ..
+
+
+Update wireless-regdb
+
+Number of VHT and DFS test cases are skipped if the old wireless-regdb
+version from Ubuntu 14.04 (2013.02.13) is used. Following steps can
+optionally be used to update wireless-regdb to a newer snapshot to
+enable additional test cases:
+
+wget http://kernel.org/pub/software/network/wireless-regdb/wireless-regdb-2014.10.07.tar.xz
+tar xJf wireless-regdb-2014.10.07.tar.xz
+sudo mv /lib/crda/regulatory.bin{,-distro}
+sudo cp wireless-regdb-2014.10.07/regulatory.bin /lib/crda/regulatory.bin
+
+# following command can be used to verify that the new version is trusted
+regdbdump /lib/crda/regulatory.bin
+
+
+Download a snapshot of the hostap.git repository and build the programs
+
+git clone git://w1.fi/hostap.git
+cd hostap/tests/hwsim
+./build.sh
+
+
+Setup is now ready for testing. You can run a quick test to confirm that
+things work as expected:
+
+# load mac80211_hwsim and start test software
+./start.sh
+
+# run a single test case ap_open
+sudo ./run-tests.py ap_open
+
+This should print out following style results:
+
+DEV: wlan0: 02:00:00:00:00:00
+DEV: wlan1: 02:00:00:00:01:00
+DEV: wlan2: 02:00:00:00:02:00
+APDEV: wlan3
+APDEV: wlan4
+START ap_open 1/1
+Test: AP with open mode (no security) configuration
+Starting AP wlan3
+Connect STA wlan0 to AP
+PASS ap_open 0.175895 2015-01-17 20:12:07.486006
+passed all 1 test case(s)
+
+(If that "PASS ap_open" line does not show up, something unexpected has
+happened and the setup is not in working condition.)
+
+# to stop test software and unload mac80211_hwsim
+./stop.sh
+
+
+To run all available test cases (about thousand or so), you can run following:
+
+./run-all.sh
+
+This will take about half an hour to hour to run (if that sounds long, see
+vm/README for information on how parallel VMs can be used to speed this
+up; e.g., a 4-core i7-4770K can run these in under 10 minutes with 7
+parallel VMs).
+
+The results may look something like this:
+
+START grpform_goneg_fail_with_group_iface 1/981
+PASS grpform_goneg_fail_with_group_iface 0.371424 2015-01-17 22:17:16.659803
+START grpform2 2/981
+PASS grpform2 1.476142 2015-01-17 22:17:18.136539
+...
+START ext_password_psk_not_found 981/981
+PASS ext_password_psk_not_found 1.544709 2015-01-17 22:46:56.489764
+failed tests: wext_wpa2_psk wext_wep_open_auth wext_open wext_rfkill wext_scan_hidden wext_pmksa_cache wext_wep_shared_key_auth
+
+
+In this example, about 860 test cases passed and about 100 were skipped.
+
+Most of the skipped test cases are in following categories:
+- D-Bus (requires kvm-based test run, see vm/README)
+- VHT 80 and 160 MHz channels (requires wireless-regdb update)
+- DFS (requires wireless-regdb updates)
+
+The following test failed every time (i.e., other failed cases could be
+passed on second attempt):
+
+wext_pmf wext_wpa2_psk wext_wep_open_auth wext_open wext_rfkill wext_scan_hidden wext_pmksa_cache wext_wep_shared_key_auth
+
+WEXT failures are due to the specific cfg80211/mac80211 version from
+Backports not allowing WEXT support to be enabled. A newer build
+addresses that and these WEXT test cases pass, e.g., with this snapshot
+build:
+http://buildbot.w1.fi/backports-wireless-testing/backports-wireless-testing-2015-01-18-ba3f765.tar.bz2
+
+With that version, ibss_rsn is failing due to a known cfg80211
+regression in the specific snapshot build. All other test cases passed
+at least on retry or were skipped due to missing testing capability.
diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config
index 14a1796..225ac24 100644
--- a/tests/hwsim/example-wpa_supplicant.config
+++ b/tests/hwsim/example-wpa_supplicant.config
@@ -52,9 +52,9 @@
 
 #CONFIG_ELOOP_POLL=y
 
-#CONFIG_CTRL_IFACE_DBUS=y
-#CONFIG_CTRL_IFACE_DBUS_NEW=y
-#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+CONFIG_CTRL_IFACE_DBUS=y
+CONFIG_CTRL_IFACE_DBUS_NEW=y
+CONFIG_CTRL_IFACE_DBUS_INTRO=y
 
 CONFIG_PEERKEY=y
 CONFIG_IEEE80211W=y
diff --git a/tests/hwsim/hostapd.wlan3.vlan b/tests/hwsim/hostapd.wlan3.vlan
new file mode 100644
index 0000000..3155e26
--- /dev/null
+++ b/tests/hwsim/hostapd.wlan3.vlan
@@ -0,0 +1 @@
+1	wlan3.1
diff --git a/tests/hwsim/hostapd.wlan4.vlan b/tests/hwsim/hostapd.wlan4.vlan
new file mode 100644
index 0000000..75ac704
--- /dev/null
+++ b/tests/hwsim/hostapd.wlan4.vlan
@@ -0,0 +1 @@
+1	wlan4.1
diff --git a/tests/hwsim/hwsim_utils.py b/tests/hwsim/hwsim_utils.py
index edf0a42..85f54a2 100644
--- a/tests/hwsim/hwsim_utils.py
+++ b/tests/hwsim/hwsim_utils.py
@@ -13,7 +13,7 @@
 from wpasupplicant import WpaSupplicant
 
 def run_connectivity_test(dev1, dev2, tos, dev1group=False, dev2group=False,
-                          ifname1=None, ifname2=None, config=True):
+                          ifname1=None, ifname2=None, config=True, timeout=5):
     addr1 = dev1.own_addr()
     if not dev1group and isinstance(dev1, WpaSupplicant):
         addr1 = dev1.get_driver_status_field('addr')
@@ -53,9 +53,9 @@
         else:
             dev1.request(cmd)
         if dev2group:
-            ev = dev2.wait_group_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev2.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
         else:
-            ev = dev2.wait_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev2.wait_event(["DATA-TEST-RX"], timeout=timeout)
         if ev is None:
             raise Exception("dev1->dev2 unicast data delivery failed")
         if "DATA-TEST-RX {} {}".format(addr2, addr1) not in ev:
@@ -67,9 +67,9 @@
         else:
             dev1.request(cmd)
         if dev2group:
-            ev = dev2.wait_group_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev2.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
         else:
-            ev = dev2.wait_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev2.wait_event(["DATA-TEST-RX"], timeout=timeout)
         if ev is None:
             raise Exception("dev1->dev2 broadcast data delivery failed")
         if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr1) not in ev:
@@ -81,9 +81,9 @@
         else:
             dev2.request(cmd)
         if dev1group:
-            ev = dev1.wait_group_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev1.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
         else:
-            ev = dev1.wait_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev1.wait_event(["DATA-TEST-RX"], timeout=timeout)
         if ev is None:
             raise Exception("dev2->dev1 unicast data delivery failed")
         if "DATA-TEST-RX {} {}".format(addr1, addr2) not in ev:
@@ -95,9 +95,9 @@
         else:
             dev2.request(cmd)
         if dev1group:
-            ev = dev1.wait_group_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev1.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
         else:
-            ev = dev1.wait_event(["DATA-TEST-RX"], timeout=5)
+            ev = dev1.wait_event(["DATA-TEST-RX"], timeout=timeout)
         if ev is None:
             raise Exception("dev2->dev1 broadcast data delivery failed")
         if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr2) not in ev:
@@ -115,7 +115,7 @@
 
 def test_connectivity(dev1, dev2, dscp=None, tos=None, max_tries=1,
                       dev1group=False, dev2group=False,
-                      ifname1=None, ifname2=None, config=True):
+                      ifname1=None, ifname2=None, config=True, timeout=5):
     if dscp:
         tos = dscp << 2
     if not tos:
@@ -126,7 +126,8 @@
     for i in range(0, max_tries):
         try:
             run_connectivity_test(dev1, dev2, tos, dev1group, dev2group,
-                                  ifname1, ifname2, config=config)
+                                  ifname1, ifname2, config=config,
+                                  timeout=timeout)
             success = True
             break
         except Exception, e:
@@ -149,3 +150,11 @@
 
 def test_connectivity_sta(dev1, dev2, dscp=None, tos=None):
     test_connectivity(dev1, dev2, dscp, tos)
+
+(PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL) = range(4)
+
+def set_powersave(dev, val):
+    phy = dev.get_driver_status_field("phyname")
+    psf = open('/sys/kernel/debug/ieee80211/%s/hwsim/ps' % phy, 'w')
+    psf.write('%d\n' % val)
+    psf.close()
diff --git a/tests/hwsim/nl80211.py b/tests/hwsim/nl80211.py
index 1abd701..440c820 100644
--- a/tests/hwsim/nl80211.py
+++ b/tests/hwsim/nl80211.py
@@ -328,6 +328,9 @@
 def build_nl80211_attr_u16(id, val):
     return build_nl80211_attr(id, struct.pack("@HH", val, 0))
 
+def build_nl80211_attr_u8(id, val):
+    return build_nl80211_attr(id, struct.pack("@4B", val, 0, 0, 0))
+
 def build_nl80211_attr_flag(id):
     return build_nl80211_attr(id, '')
 
diff --git a/tests/hwsim/rfkill.py b/tests/hwsim/rfkill.py
new file mode 100755
index 0000000..cf73f4f
--- /dev/null
+++ b/tests/hwsim/rfkill.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+#
+# rfkill control code
+#
+# Copyright (c) 2015	Intel Corporation
+#
+# Author: Johannes Berg <johannes.berg@intel.com>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import struct
+import fcntl
+import os
+
+(TYPE_ALL,
+ TYPE_WLAN,
+ TYPE_BLUETOOTH,
+ TYPE_UWB,
+ TYPE_WIMAX,
+ TYPE_WWAN,
+ TYPE_GPS,
+ TYPE_FM,
+ TYPE_NFC) = range(9)
+
+(_OP_ADD,
+ _OP_DEL,
+ _OP_CHANGE,
+ _OP_CHANGE_ALL) = range(4)
+
+_type_names = {
+    TYPE_ALL: "all",
+    TYPE_WLAN: "Wireless LAN",
+    TYPE_BLUETOOTH: "Bluetooth",
+    TYPE_UWB: "Ultra-Wideband",
+    TYPE_WIMAX: "WiMAX",
+    TYPE_WWAN: "Wireless WAN",
+    TYPE_GPS: "GPS",
+    TYPE_FM: "FM",
+    TYPE_NFC: "NFC",
+}
+
+# idx, type, op, soft, hard
+_event_struct = '@IBBBB'
+_event_sz = struct.calcsize(_event_struct)
+
+class RFKillException(Exception):
+    pass
+
+class RFKill(object):
+    def __init__(self, idx):
+        self._idx = idx
+        self._type = None
+
+    @property
+    def idx(self):
+        return self._idx
+
+    @property
+    def name(self):
+        return open('/sys/class/rfkill/rfkill%d/name' % self._idx, 'r').read().rstrip()
+
+    @property
+    def type(self):
+        if not self._type:
+            for r, s, h in RFKill.list():
+                if r.idx == self.idx:
+                    self._type = r._type
+                    break
+        return self._type
+
+    @property
+    def type_name(self):
+        return _type_names.get(self._type, "unknown")
+
+    @property
+    def blocked(self):
+        l = RFKill.list()
+        for r, s, h in l:
+            if r.idx == self.idx:
+                return (s, h)
+        raise RFKillException("RFKill instance no longer exists")
+
+    @property
+    def soft_blocked(self):
+        return self.blocked[0]
+        
+    @soft_blocked.setter
+    def soft_blocked(self, block):
+        if block:
+            self.block()
+        else:
+            self.unblock()
+
+    @property
+    def hard_blocked(self):
+        return self.blocked[1]
+
+    def block(self):
+        rfk = open('/dev/rfkill', 'w')
+        s = struct.pack(_event_struct, self.idx, TYPE_ALL, _OP_CHANGE, 1, 0)
+        rfk.write(s)
+        rfk.close()
+
+    def unblock(self):
+        rfk = open('/dev/rfkill', 'w')
+        s = struct.pack(_event_struct, self.idx, TYPE_ALL, _OP_CHANGE, 0, 0)
+        rfk.write(s)
+        rfk.close()
+
+    @classmethod
+    def block_all(cls, t=TYPE_ALL):
+        rfk = open('/dev/rfkill', 'w')
+        print rfk
+        s = struct.pack(_event_struct, 0, t, _OP_CHANGE_ALL, 1, 0)
+        rfk.write(s)
+        rfk.close()
+
+    @classmethod
+    def unblock_all(cls, t=TYPE_ALL):
+        rfk = open('/dev/rfkill', 'w')
+        s = struct.pack(_event_struct, 0, t, _OP_CHANGE_ALL, 0, 0)
+        rfk.write(s)
+        rfk.close()
+
+    @classmethod
+    def list(cls):
+        res = []
+        rfk = open('/dev/rfkill', 'r')
+        fd = rfk.fileno()
+        flgs = fcntl.fcntl(fd, fcntl.F_GETFL)
+        fcntl.fcntl(fd, fcntl.F_SETFL, flgs | os.O_NONBLOCK)
+        while True:
+            try:
+                d = rfk.read(_event_sz)
+                _idx, _t, _op, _s, _h = struct.unpack(_event_struct, d)
+                if _op != _OP_ADD:
+                    continue
+                r = RFKill(_idx)
+                r._type = _t
+                res.append((r, _s, _h))
+            except IOError:
+                break
+        return res
+
+if __name__ == "__main__":
+    for r, s, h in RFKill.list():
+        print "%d: %s: %s" % (r.idx, r.name, r.type_name)
+        print "\tSoft blocked: %s" % ("yes" if s else "no")
+        print "\tHard blocked: %s" % ("yes" if h else "no")
diff --git a/tests/hwsim/run-tests.py b/tests/hwsim/run-tests.py
index 3e8f86f..7e9c4a2 100755
--- a/tests/hwsim/run-tests.py
+++ b/tests/hwsim/run-tests.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python2
 #
 # Test case executor
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -18,15 +18,14 @@
 import logging
 logger = logging.getLogger()
 
-if os.path.exists('../../wpaspy'):
-    sys.path.append('../../wpaspy')
-else:
-    sys.path.append('../../../wpaspy')
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
 
 from wpasupplicant import WpaSupplicant
 from hostapd import HostapdGlobal
 from check_kernel import check_kernel
 from wlantest import Wlantest
+from utils import HwsimSkip
 
 def set_term_echo(fd, enabled):
     [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] = termios.tcgetattr(fd)
@@ -47,6 +46,7 @@
             print str(e)
             ok = False
 
+    wpas = None
     try:
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         ifaces = wpas.global_request("INTERFACES").splitlines()
@@ -55,6 +55,8 @@
                 wpas.interface_remove(iface)
     except Exception, e:
         pass
+    if wpas:
+        wpas.close_ctrl()
 
     try:
         hapd = HostapdGlobal()
@@ -120,7 +122,7 @@
     def __enter__(self):
         if self._tracing:
             output = os.path.abspath(os.path.join(self._logdir, '%s.dat' % (self._testname, )))
-            self._trace_cmd = subprocess.Popen(['sudo', 'trace-cmd', 'record', '-o', output, '-e', 'mac80211', '-e', 'cfg80211', 'sh', '-c', 'echo STARTED ; read l'],
+            self._trace_cmd = subprocess.Popen(['trace-cmd', 'record', '-o', output, '-e', 'mac80211', '-e', 'cfg80211', '-e', 'printk', 'sh', '-c', 'echo STARTED ; read l'],
                                                stdin=subprocess.PIPE,
                                                stdout=subprocess.PIPE,
                                                stderr=open('/dev/null', 'w'),
@@ -138,7 +140,11 @@
             self._trace_cmd.wait()
         if self._dmesg:
             output = os.path.join(self._logdir, '%s.dmesg' % (self._testname, ))
-            subprocess.call(['sudo', 'dmesg', '-c'], stdout=open(output, 'w'))
+            num = 0
+            while os.path.exists(output):
+                output = os.path.join(self._logdir, '%s.dmesg-%d' % (self._testname, num))
+                num += 1
+            subprocess.call(['dmesg', '-c'], stdout=open(output, 'w'))
 
 def rename_log(logdir, basename, testname, dev):
     try:
@@ -153,7 +159,7 @@
         os.rename(srcname, dstname)
         if dev:
             dev.relog()
-            subprocess.call(['sudo', 'chown', '-f', getpass.getuser(), srcname])
+            subprocess.call(['chown', '-f', getpass.getuser(), srcname])
     except Exception, e:
         logger.info("Failed to rename log files")
         logger.info(e)
@@ -161,10 +167,7 @@
 def main():
     tests = []
     test_modules = []
-    if os.path.exists('run-tests.py'):
-        files = os.listdir(".")
-    else:
-        files = os.listdir("..")
+    files = os.listdir(scriptsdir)
     for t in files:
         m = re.match(r'(test_.*)\.py$', t)
         if m:
@@ -334,7 +337,7 @@
         sys.exit(1)
 
     if args.dmesg:
-        subprocess.call(['sudo', 'dmesg', '-c'], stdout=open('/dev/null', 'w'))
+        subprocess.call(['dmesg', '-c'], stdout=open('/dev/null', 'w'))
 
     if conn and args.prefill:
         for t in tests_to_run:
@@ -432,15 +435,15 @@
                     params = {}
                     params['logdir'] = args.logdir
                     params['long'] = args.long
-                    res = t(dev, apdev, params)
+                    t(dev, apdev, params)
                 elif t.func_code.co_argcount > 1:
-                    res = t(dev, apdev)
+                    t(dev, apdev)
                 else:
-                    res = t(dev)
-                if res == "skip":
-                    result = "SKIP"
-                else:
-                    result = "PASS"
+                    t(dev)
+                result = "PASS"
+            except HwsimSkip, e:
+                logger.info("Skip test case: %s" % e)
+                result = "SKIP"
             except Exception, e:
                 logger.info(e)
                 if args.loglevel == logging.WARNING:
@@ -454,14 +457,16 @@
                     logger.info("Failed to issue TEST-STOP after {} for {}".format(name, d.ifname))
                     logger.info(e)
                     result = "FAIL"
+            wpas = None
             try:
-                wpas = WpaSupplicant("/tmp/wpas-wlan5")
-                d.dump_monitor()
+                wpas = WpaSupplicant(global_iface="/tmp/wpas-wlan5")
                 rename_log(args.logdir, 'log5', name, wpas)
                 if not args.no_reset:
                     wpas.remove_ifname()
             except Exception, e:
                 pass
+            if wpas:
+                wpas.close_ctrl()
             if args.no_reset:
                 print "Leaving devices in current state"
             else:
diff --git a/tests/hwsim/start.sh b/tests/hwsim/start.sh
index 602e4b8..df8a76d 100755
--- a/tests/hwsim/start.sh
+++ b/tests/hwsim/start.sh
@@ -65,8 +65,8 @@
     sed "s/ GROUP=.*$/ GROUP=$GROUP/" "$DIR/p2p$i.conf" > "$LOGDIR/p2p$i.conf"
 done
 
-sed "s/group=admin/group=$GROUP/" "$DIR/auth_serv/as.conf" > "$LOGDIR/as.conf"
-sed "s/group=admin/group=$GROUP/;s%LOGDIR%$LOGDIR%" "$DIR/auth_serv/as2.conf" > "$LOGDIR/as2.conf"
+sed "s/group=admin/group=$GROUP/;s%LOGDIR%$LOGDIR%g" "$DIR/auth_serv/as.conf" > "$LOGDIR/as.conf"
+sed "s/group=admin/group=$GROUP/;s%LOGDIR%$LOGDIR%g" "$DIR/auth_serv/as2.conf" > "$LOGDIR/as2.conf"
 
 if [ "$1" = "valgrind" ]; then
     VALGRIND=y
@@ -104,8 +104,14 @@
 sudo ifconfig hwsim0 up
 sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dt -L $LOGDIR/hwsim0 &
 for i in 0 1 2; do
+    DBUSARG=""
+    if [ $i = "0" -a -r /var/run/dbus/pid -a -r /var/run/dbus/hwsim-test ]; then
+	if $WPAS | grep -q -- -u; then
+	    DBUSARG="-u"
+	fi
+    fi
     sudo $(printf -- "$VALGRIND_WPAS" $i) $WPAS -g /tmp/wpas-wlan$i -G$GROUP -Dnl80211 -iwlan$i -c $LOGDIR/p2p$i.conf \
-         -ddKt$TRACE -f $LOGDIR/log$i &
+         -ddKt$TRACE -f $LOGDIR/log$i $DBUSARG &
 done
 sudo $(printf -- "$VALGRIND_WPAS" 5) $WPAS -g /tmp/wpas-wlan5 -G$GROUP \
     -ddKt$TRACE -f $LOGDIR/log5 &
@@ -116,6 +122,30 @@
     sudo $HLR_AUC_GW -u -m $LOGDIR/hlr_auc_gw.milenage_db -g $DIR/auth_serv/hlr_auc_gw.gsm > $LOGDIR/hlr_auc_gw &
 fi
 
+openssl ocsp -index $DIR/auth_serv/index.txt \
+    -rsigner $DIR/auth_serv/ocsp-responder.pem \
+    -rkey $DIR/auth_serv/ocsp-responder.key \
+    -CA $DIR/auth_serv/ca.pem \
+    -issuer $DIR/auth_serv/ca.pem \
+    -verify_other $DIR/auth_serv/ca.pem -trust_other \
+    -ndays 7 \
+    -reqin $DIR/auth_serv/ocsp-req.der \
+    -respout $LOGDIR/ocsp-server-cache.der > $LOGDIR/ocsp.log 2>&1
+if [ ! -r $LOGDIR/ocsp-server-cache.der ]; then
+    cp $DIR/auth_serv/ocsp-server-cache.der $LOGDIR/ocsp-server-cache.der
+fi
+
+for i in unknown revoked; do
+    openssl ocsp -index $DIR/auth_serv/index-$i.txt \
+	-rsigner $DIR/auth_serv/ocsp-responder.pem \
+	-rkey $DIR/auth_serv/ocsp-responder.key \
+	-CA $DIR/auth_serv/ca.pem \
+	-issuer $DIR/auth_serv/ca.pem \
+	-verify_other $DIR/auth_serv/ca.pem -trust_other \
+	-ndays 7 \
+	-reqin $DIR/auth_serv/ocsp-req.der \
+	-respout $LOGDIR/ocsp-server-cache-$i.der >> $LOGDIR/ocsp.log 2>&1
+done
 touch $LOGDIR/hostapd.db
 sudo $HAPD_AS -ddKt $LOGDIR/as.conf $LOGDIR/as2.conf > $LOGDIR/auth_serv &
 
diff --git a/tests/hwsim/test_ap_acs.py b/tests/hwsim/test_ap_acs.py
index c0b559b..a7dfd06 100644
--- a/tests/hwsim/test_ap_acs.py
+++ b/tests/hwsim/test_ap_acs.py
@@ -10,6 +10,24 @@
 import time
 
 import hostapd
+from test_ap_ht import clear_scan_cache
+
+def force_prev_ap_on_24g(ap):
+    # For now, make sure the last operating channel was on 2.4 GHz band to get
+    # sufficient survey data from mac80211_hwsim.
+    hostapd.add_ap(ap['ifname'], { "ssid": "open" })
+    time.sleep(0.1)
+    hapd_global = hostapd.HostapdGlobal()
+    hapd_global.remove(ap['ifname'])
+
+def force_prev_ap_on_5g(ap):
+    # For now, make sure the last operating channel was on 5 GHz band to get
+    # sufficient survey data from mac80211_hwsim.
+    hostapd.add_ap(ap['ifname'], { "ssid": "open", "hw_mode": "a",
+                                   "channel": "36", "country_code": "US" })
+    time.sleep(0.1)
+    hapd_global = hostapd.HostapdGlobal()
+    hapd_global.remove(ap['ifname'])
 
 def wait_acs(hapd):
     ev = hapd.wait_event(["ACS-STARTED", "ACS-COMPLETED", "ACS-FAILED",
@@ -42,6 +60,7 @@
 
 def test_ap_acs(dev, apdev):
     """Automatic channel selection"""
+    force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
@@ -56,13 +75,7 @@
 def test_ap_multi_bss_acs(dev, apdev):
     """hostapd start with a multi-BSS configuration file using ACS"""
     ifname = apdev[0]['ifname']
-
-    # make sure the current channel is on 2.4 GHz band as a workaround for the
-    # limited survey functionality in mac80211_hwsim
-    hostapd.add_ap(ifname, { "ssid": "test" })
-    time.sleep(0.1)
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ifname)
+    force_prev_ap_on_24g(apdev[0])
 
     # start the actual test
     hostapd.add_iface(ifname, 'multi-bss-acs.conf')
@@ -80,6 +93,8 @@
 
 def test_ap_acs_40mhz(dev, apdev):
     """Automatic channel selection for 40 MHz channel"""
+    clear_scan_cache(apdev[0]['ifname'])
+    force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
     params['ht_capab'] = '[HT40+]'
@@ -99,75 +114,60 @@
     """Automatic channel selection on 5 GHz"""
     try:
         hapd = None
+        force_prev_ap_on_5g(apdev[0])
         params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
         params['hw_mode'] = 'a'
         params['channel'] = '0'
         params['country_code'] = 'US'
         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
-        # TODO: Remove exception acceptance once mac80211_hwsim supports ACS on
-        # 5 GHz
-        run = False
-        try:
-            wait_acs(hapd)
-            run = True
-        except Exception, e:
-            logger.info("Ignore exception due to missing hwsim support: " + str(e))
+        wait_acs(hapd)
+        freq = hapd.get_status_field("freq")
+        if int(freq) < 5000:
+            raise Exception("Unexpected frequency")
 
-        if run:
-            freq = hapd.get_status_field("freq")
-            if int(freq) < 5000:
-                raise Exception("Unexpected frequency")
-
-            dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
+        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
 
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acs_5ghz_40mhz(dev, apdev):
     """Automatic channel selection on 5 GHz for 40 MHz channel"""
     try:
         hapd = None
+        force_prev_ap_on_5g(apdev[0])
         params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
         params['hw_mode'] = 'a'
         params['channel'] = '0'
         params['ht_capab'] = '[HT40+]'
         params['country_code'] = 'US'
         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
-        # TODO: Remove exception acceptance once mac80211_hwsim supports ACS on
-        # 5 GHz
-        run = False
-        try:
-            wait_acs(hapd)
-            run = True
-        except Exception, e:
-            logger.info("Ignore exception due to missing hwsim support: " + str(e))
+        wait_acs(hapd)
+        freq = hapd.get_status_field("freq")
+        if int(freq) < 5000:
+            raise Exception("Unexpected frequency")
 
-        if run:
-            freq = hapd.get_status_field("freq")
-            if int(freq) < 5000:
-                raise Exception("Unexpected frequency")
+        sec = hapd.get_status_field("secondary_channel")
+        if int(sec) == 0:
+            raise Exception("Secondary channel not set")
 
-            sec = hapd.get_status_field("secondary_channel")
-            if int(sec) == 0:
-                raise Exception("Secondary channel not set")
-
-            dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
+        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
 
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acs_vht(dev, apdev):
     """Automatic channel selection for VHT"""
     try:
         hapd = None
+        force_prev_ap_on_5g(apdev[0])
         params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
         params['hw_mode'] = 'a'
         params['channel'] = '0'
@@ -176,29 +176,35 @@
         params['ieee80211ac'] = '1'
         params['vht_oper_chwidth'] = '1'
         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
-        # TODO: Remove exception acceptance once mac80211_hwsim supports ACS on
-        # 5 GHz
-        run = False
-        try:
-            wait_acs(hapd)
-            run = True
-        except Exception, e:
-            logger.info("Ignore exception due to missing hwsim support: " + str(e))
+        wait_acs(hapd)
+        freq = hapd.get_status_field("freq")
+        if int(freq) < 5000:
+            raise Exception("Unexpected frequency")
 
-        if run:
-            freq = hapd.get_status_field("freq")
-            if int(freq) < 5000:
-                raise Exception("Unexpected frequency")
+        sec = hapd.get_status_field("secondary_channel")
+        if int(sec) == 0:
+            raise Exception("Secondary channel not set")
 
-            sec = hapd.get_status_field("secondary_channel")
-            if int(sec) == 0:
-                raise Exception("Secondary channel not set")
-
-            dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
+        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
 
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
+
+def test_ap_acs_bias(dev, apdev):
+    """Automatic channel selection with bias values"""
+    force_prev_ap_on_24g(apdev[0])
+    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
+    params['channel'] = '0'
+    params['acs_chan_bias'] = '1:0.8 3:1.2 6:0.7 11:0.8'
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    wait_acs(hapd)
+
+    freq = hapd.get_status_field("freq")
+    if int(freq) < 2400:
+        raise Exception("Unexpected frequency")
+
+    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
diff --git a/tests/hwsim/test_ap_ciphers.py b/tests/hwsim/test_ap_ciphers.py
index 01b5d45..a1ddcad 100644
--- a/tests/hwsim/test_ap_ciphers.py
+++ b/tests/hwsim/test_ap_ciphers.py
@@ -11,10 +11,12 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
+from wlantest import Wlantest
 
 def check_cipher(dev, ap, cipher):
     if cipher not in dev.get_capability("pairwise"):
-        return "skip"
+        raise HwsimSkip("Cipher %s not supported" % cipher)
     params = { "ssid": "test-wpa2-psk",
                "wpa_passphrase": "12345678",
                "wpa": "2",
@@ -25,15 +27,49 @@
                 pairwise=cipher, group=cipher, scan_freq="2412")
     hwsim_utils.test_connectivity(dev, hapd)
 
+def check_group_mgmt_cipher(dev, ap, cipher):
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+
+    if cipher not in dev.get_capability("group_mgmt"):
+        raise HwsimSkip("Cipher %s not supported" % cipher)
+    params = { "ssid": "test-wpa2-psk-pmf",
+               "wpa_passphrase": "12345678",
+               "wpa": "2",
+               "ieee80211w": "2",
+               "wpa_key_mgmt": "WPA-PSK-SHA256",
+               "rsn_pairwise": "CCMP",
+               "group_mgmt_cipher": cipher }
+    hapd = hostapd.add_ap(ap['ifname'], params)
+    dev.connect("test-wpa2-psk-pmf", psk="12345678", ieee80211w="2",
+                key_mgmt="WPA-PSK-SHA256",
+                pairwise="CCMP", group="CCMP", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev, hapd)
+    hapd.request("DEAUTHENTICATE ff:ff:ff:ff:ff:ff")
+    dev.wait_disconnected()
+    if wt.get_bss_counter('valid_bip_mmie', ap['bssid']) < 1:
+        raise Exception("No valid BIP MMIE seen")
+    if wt.get_bss_counter('bip_deauth', ap['bssid']) < 1:
+        raise Exception("No valid BIP deauth seen")
+
+    if cipher == "AES-128-CMAC":
+        group_mgmt = "BIP"
+    else:
+        group_mgmt = cipher
+    res =  wt.info_bss('group_mgmt', ap['bssid']).strip()
+    if res != group_mgmt:
+        raise Exception("Unexpected group mgmt cipher: " + res)
+
 def test_ap_cipher_tkip(dev, apdev):
     """WPA2-PSK/TKIP connection"""
-    return check_cipher(dev[0], apdev[0], "TKIP")
+    check_cipher(dev[0], apdev[0], "TKIP")
 
 def test_ap_cipher_tkip_countermeasures_ap(dev, apdev):
     """WPA-PSK/TKIP countermeasures (detected by AP)"""
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (dev[0].get_driver_status_field("phyname"), dev[0].ifname)
     if not os.path.exists(testfile):
-        return "skip"
+        raise HwsimSkip("tkip_mic_test not supported in mac80211")
 
     params = { "ssid": "tkip-countermeasures",
                "wpa_passphrase": "12345678",
@@ -73,7 +109,7 @@
 
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (hapd.get_driver_status_field("phyname"), apdev[0]['ifname'])
     if not os.path.exists(testfile):
-        return "skip"
+        raise HwsimSkip("tkip_mic_test not supported in mac80211")
 
     dev[0].connect("tkip-countermeasures", psk="12345678",
                    pairwise="TKIP", group="TKIP", scan_freq="2412")
@@ -97,19 +133,19 @@
 
 def test_ap_cipher_ccmp(dev, apdev):
     """WPA2-PSK/CCMP connection"""
-    return check_cipher(dev[0], apdev[0], "CCMP")
+    check_cipher(dev[0], apdev[0], "CCMP")
 
 def test_ap_cipher_gcmp(dev, apdev):
     """WPA2-PSK/GCMP connection"""
-    return check_cipher(dev[0], apdev[0], "GCMP")
+    check_cipher(dev[0], apdev[0], "GCMP")
 
 def test_ap_cipher_ccmp_256(dev, apdev):
     """WPA2-PSK/CCMP-256 connection"""
-    return check_cipher(dev[0], apdev[0], "CCMP-256")
+    check_cipher(dev[0], apdev[0], "CCMP-256")
 
 def test_ap_cipher_gcmp_256(dev, apdev):
     """WPA2-PSK/GCMP-256 connection"""
-    return check_cipher(dev[0], apdev[0], "GCMP-256")
+    check_cipher(dev[0], apdev[0], "GCMP-256")
 
 def test_ap_cipher_mixed_wpa_wpa2(dev, apdev):
     """WPA2-PSK/CCMP/ and WPA-PSK/TKIP mixed configuration"""
@@ -151,3 +187,19 @@
         raise Exception("Incorrect group_cipher reported")
     hwsim_utils.test_connectivity(dev[1], hapd)
     hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_ap_cipher_bip(dev, apdev):
+    """WPA2-PSK with BIP"""
+    check_group_mgmt_cipher(dev[0], apdev[0], "AES-128-CMAC")
+
+def test_ap_cipher_bip_gmac_128(dev, apdev):
+    """WPA2-PSK with BIP-GMAC-128"""
+    check_group_mgmt_cipher(dev[0], apdev[0], "BIP-GMAC-128")
+
+def test_ap_cipher_bip_gmac_256(dev, apdev):
+    """WPA2-PSK with BIP-GMAC-256"""
+    check_group_mgmt_cipher(dev[0], apdev[0], "BIP-GMAC-256")
+
+def test_ap_cipher_bip_cmac_256(dev, apdev):
+    """WPA2-PSK with BIP-CMAC-256"""
+    check_group_mgmt_cipher(dev[0], apdev[0], "BIP-CMAC-256")
diff --git a/tests/hwsim/test_ap_csa.py b/tests/hwsim/test_ap_csa.py
index ebf926f..c88e517 100644
--- a/tests/hwsim/test_ap_csa.py
+++ b/tests/hwsim/test_ap_csa.py
@@ -10,6 +10,7 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
 
 def connect(dev, apdev):
     params = { "ssid": "ap-csa",
@@ -31,12 +32,12 @@
 # WpaSupplicant or Hostapd supports CSA.
 def csa_supported(dev):
     res = dev.get_driver_status()
-    return (int(res['capa.flags'], 0) & 0x80000000) != 0
+    if (int(res['capa.flags'], 0) & 0x80000000) == 0:
+        raise HwsimSkip("CSA not supported")
 
 def test_ap_csa_1_switch(dev, apdev):
     """AP Channel Switch, one switch"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -45,8 +46,7 @@
 
 def test_ap_csa_2_switches(dev, apdev):
     """AP Channel Switch, two switches"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -57,8 +57,7 @@
 
 def test_ap_csa_1_switch_count_0(dev, apdev):
     """AP Channel Switch, one switch with count 0"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -68,8 +67,7 @@
 
 def test_ap_csa_2_switches_count_0(dev, apdev):
     """AP Channel Switch, two switches with count 0"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -82,8 +80,7 @@
 
 def test_ap_csa_1_switch_count_1(dev, apdev):
     """AP Channel Switch, one switch with count 1"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -93,8 +90,7 @@
 
 def test_ap_csa_2_switches_count_1(dev, apdev):
     """AP Channel Switch, two switches with count 1"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
@@ -107,8 +103,7 @@
 
 def test_ap_csa_1_switch_count_2(dev, apdev):
     """AP Channel Switch, one switch with count 2"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     ap = connect(dev[0], apdev)
 
     hwsim_utils.test_connectivity(dev[0], ap)
diff --git a/tests/hwsim/test_ap_dynamic.py b/tests/hwsim/test_ap_dynamic.py
index c0b8aa8..e8836ca 100644
--- a/tests/hwsim/test_ap_dynamic.py
+++ b/tests/hwsim/test_ap_dynamic.py
@@ -12,6 +12,8 @@
 
 import hwsim_utils
 import hostapd
+from utils import alloc_fail
+from test_ap_acs import force_prev_ap_on_24g
 
 def test_ap_change_ssid(dev, apdev):
     """Dynamic SSID change with hostapd and WPA2-PSK"""
@@ -34,7 +36,7 @@
     dev[0].set_network_quoted(id, "ssid", "test-wpa2-psk-new")
     dev[0].connect_network(id)
 
-def multi_check(dev, check):
+def multi_check(dev, check, scan_opt=True):
     id = []
     num_bss = len(check)
     for i in range(0, num_bss):
@@ -48,6 +50,9 @@
     for i in range(num_bss):
         if not check[i]:
             continue
+        bssid = '02:00:00:00:03:0' + str(i)
+        if scan_opt:
+            dev[i].scan_for_bss(bssid, freq=2412)
         id.append(dev[i].connect("bss-" + str(i + 1), key_mgmt="NONE",
                                  scan_freq="2412", wait_connect=True))
     first = True
@@ -77,6 +82,15 @@
 
 def test_ap_bss_add_remove(dev, apdev):
     """Dynamic BSS add/remove operations with hostapd"""
+    try:
+        _test_ap_bss_add_remove(dev, apdev)
+    finally:
+        for i in range(3):
+            dev[i].request("SCAN_INTERVAL 5")
+
+def _test_ap_bss_add_remove(dev, apdev):
+    for i in range(3):
+        dev[i].request("SCAN_INTERVAL 1")
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
     ifname3 = apdev[0]['ifname'] + '-3'
@@ -142,14 +156,14 @@
     ifname2 = apdev[0]['ifname'] + '-2'
     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
     hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
-    multi_check(dev, [ True, True ])
+    multi_check(dev, [ True, True ], scan_opt=False)
     hostapd.remove_bss(ifname2)
     hostapd.remove_bss(ifname1)
 
     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
     hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
     hostapd.remove_bss(ifname2)
-    multi_check(dev, [ True, False ])
+    multi_check(dev, [ True, False ], scan_opt=False)
     hostapd.remove_bss(ifname1)
 
     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
@@ -220,6 +234,7 @@
 
 def test_ap_remove_during_acs(dev, apdev):
     """Remove interface during ACS"""
+    force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs-remove", passphrase="12345678")
     params['channel'] = '0'
     ifname = apdev[0]['ifname']
@@ -229,6 +244,7 @@
 
 def test_ap_remove_during_acs2(dev, apdev):
     """Remove BSS during ACS in multi-BSS configuration"""
+    force_prev_ap_on_24g(apdev[0])
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
     hapd_global = hostapd.HostapdGlobal()
@@ -244,6 +260,7 @@
 
 def test_ap_remove_during_acs3(dev, apdev):
     """Remove second BSS during ACS in multi-BSS configuration"""
+    force_prev_ap_on_24g(apdev[0])
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
     hapd_global = hostapd.HostapdGlobal()
@@ -395,3 +412,57 @@
     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
     hostapd.remove_bss(ifname2)
     subprocess.check_call(["iw", "dev", ifname2, "del"])
+
+def hapd_bss_out_of_mem(hapd, phy, confname, count, func):
+    with alloc_fail(hapd, count, func):
+        hapd_global = hostapd.HostapdGlobal()
+        res = hapd_global.ctrl.request("ADD bss_config=" + phy + ":" + confname)
+        if "OK" in res:
+            raise Exception("add_bss succeeded")
+
+def test_ap_bss_add_out_of_memory(dev, apdev):
+    """Running out of memory while adding a BSS"""
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+
+    ifname1 = apdev[0]['ifname']
+    ifname2 = apdev[0]['ifname'] + '-2'
+
+    hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf', 1, 'hostapd_add_iface')
+    for i in range(1, 3):
+        hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf',
+                            i, 'hostapd_interface_init_bss')
+    hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf',
+                        1, 'ieee802_11_build_ap_params')
+
+    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+
+    hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
+                        1, 'hostapd_interface_init_bss')
+    hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
+                        1, 'ieee802_11_build_ap_params')
+
+    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.remove_bss(ifname2)
+    hostapd.remove_bss(ifname1)
+
+def test_ap_multi_bss(dev, apdev):
+    """Multiple BSSes with hostapd"""
+    ifname1 = apdev[0]['ifname']
+    ifname2 = apdev[0]['ifname'] + '-2'
+    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    dev[0].connect("bss-1", key_mgmt="NONE", scan_freq="2412")
+    dev[1].connect("bss-2", key_mgmt="NONE", scan_freq="2412")
+
+    hapd1 = hostapd.Hostapd(ifname1)
+    hapd2 = hostapd.Hostapd(ifname2)
+
+    hwsim_utils.test_connectivity(dev[0], hapd1)
+    hwsim_utils.test_connectivity(dev[1], hapd2)
+
+    sta0 = hapd1.get_sta(dev[0].own_addr())
+    sta1 = hapd2.get_sta(dev[1].own_addr())
+    if 'rx_packets' not in sta0 or int(sta0['rx_packets']) < 1:
+        raise Exception("sta0 did not report receiving packets")
+    if 'rx_packets' not in sta1 or int(sta1['rx_packets']) < 1:
+        raise Exception("sta1 did not report receiving packets")
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index e14b470..a75f8fa 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-
 # WPA2-Enterprise tests
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
 import base64
+import binascii
 import time
 import subprocess
 import logging
@@ -14,7 +15,38 @@
 
 import hwsim_utils
 import hostapd
-from test_ap_psk import check_mib
+from utils import HwsimSkip, alloc_fail
+from wpasupplicant import WpaSupplicant
+from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations
+
+def check_hlr_auc_gw_support():
+    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
+        raise HwsimSkip("No hlr_auc_gw available")
+
+def check_eap_capa(dev, method):
+    res = dev.get_capability("eap")
+    if method not in res:
+        raise HwsimSkip("EAP method %s not supported in the build" % method)
+
+def check_subject_match_support(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("subject_match not supported with this TLS library: " + tls)
+
+def check_altsubject_match_support(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls)
+
+def check_domain_match_full(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("domain_suffix_match requires full match with this TLS library: " + tls)
+
+def check_cert_probe_support(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("Certificate probing not supported with this TLS library: " + tls)
 
 def read_pem(fname):
     with open(fname, "r") as f:
@@ -102,9 +134,7 @@
 
 def test_ap_wpa2_eap_sim(dev, apdev):
     """WPA2-Enterprise connection using EAP-SIM"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
@@ -155,13 +185,11 @@
 
 def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
     """WPA2-Enterprise connection using EAP-SIM (SQL)"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     try:
         import sqlite3
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No sqlite3 module available")
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
@@ -247,14 +275,12 @@
 def test_ap_wpa2_eap_sim_ext(dev, apdev):
     """WPA2-Enterprise connection using EAP-SIM and external GSM auth"""
     try:
-        return _test_ap_wpa2_eap_sim_ext(dev, apdev)
+        _test_ap_wpa2_eap_sim_ext(dev, apdev)
     finally:
         dev[0].request("SET external_sim 0")
 
 def _test_ap_wpa2_eap_sim_ext(dev, apdev):
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].request("SET external_sim 1")
@@ -281,6 +307,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -297,6 +325,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -313,6 +343,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -329,6 +361,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -345,6 +379,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -361,6 +397,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -379,9 +417,7 @@
 
 def test_ap_wpa2_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-AKA"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
@@ -435,13 +471,11 @@
 
 def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
     """WPA2-Enterprise connection using EAP-AKA (SQL)"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     try:
         import sqlite3
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No sqlite3 module available")
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
@@ -504,14 +538,12 @@
 def test_ap_wpa2_eap_aka_ext(dev, apdev):
     """WPA2-Enterprise connection using EAP-AKA and external UMTS auth"""
     try:
-        return _test_ap_wpa2_eap_aka_ext(dev, apdev)
+        _test_ap_wpa2_eap_aka_ext(dev, apdev)
     finally:
         dev[0].request("SET external_sim 0")
 
 def _test_ap_wpa2_eap_aka_ext(dev, apdev):
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].request("SET external_sim 1")
@@ -539,22 +571,8 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
-
-    dev[0].request("REASSOCIATE")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:" + resp):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -581,107 +599,38 @@
     if ev is None:
         raise Exception("EAP failure not reported")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    time.sleep(0.1)
 
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:34"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
-
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:00112233445566778899aabbccddeeff.00112233445566778899aabbccddeeff:0011223344"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
-
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddee:0011223344"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
-
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff.0011223344"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
-
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff0011223344"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
-    dev[0].request("DISCONNECT")
-
-    dev[0].select_network(id, freq="2412")
-    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
-    if ev is None:
-        raise Exception("Wait for external SIM processing request timed out")
-    p = ev.split(':', 2)
-    if p[1] != "UMTS-AUTH":
-        raise Exception("Unexpected CTRL-REQ-SIM type")
-    rid = p[0].split('-')[3]
-    # This will fail during UMTS auth validation
-    if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:001122334q"):
-        raise Exception("CTRL-RSP-SIM failed")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
-    if ev is None:
-        raise Exception("EAP failure not reported")
+    tests = [ ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:0011223344",
+              ":UMTS-AUTH:34",
+              ":UMTS-AUTH:00112233445566778899aabbccddeeff.00112233445566778899aabbccddeeff:0011223344",
+              ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddee:0011223344",
+              ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff.0011223344",
+              ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff0011223344",
+              ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:001122334q" ]
+    for t in tests:
+        dev[0].select_network(id, freq="2412")
+        ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+        if ev is None:
+            raise Exception("Wait for external SIM processing request timed out")
+        p = ev.split(':', 2)
+        if p[1] != "UMTS-AUTH":
+            raise Exception("Unexpected CTRL-REQ-SIM type")
+        rid = p[0].split('-')[3]
+        # This will fail during UMTS auth validation
+        if "OK" not in dev[0].request("CTRL-RSP-SIM-" + rid + t):
+            raise Exception("CTRL-RSP-SIM failed")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
+        if ev is None:
+            raise Exception("EAP failure not reported")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected()
+        time.sleep(0.1)
 
 def test_ap_wpa2_eap_aka_prime(dev, apdev):
     """WPA2-Enterprise connection using EAP-AKA'"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
@@ -704,13 +653,11 @@
 
 def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params):
     """WPA2-Enterprise connection using EAP-AKA' (SQL)"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     try:
         import sqlite3
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No sqlite3 module available")
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
@@ -771,14 +718,25 @@
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
     eap_connect(dev[0], apdev[0], "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
-                ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
-                subject_match="/C=FI/O=w1.fi/CN=server.w1.fi",
-                altsubject_match="EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/")
+                ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "TTLS")
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-1"),
                         ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-1") ])
 
+def test_ap_wpa2_eap_ttls_pap_subject_match(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/PAP and (alt)subject_match"""
+    check_subject_match_support(dev[0])
+    check_altsubject_match_support(dev[0])
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                subject_match="/C=FI/O=w1.fi/CN=server.w1.fi",
+                altsubject_match="EMAIL:noone@example.com;DNS:server.w1.fi;URI:http://example.com/")
+    eap_reauth(dev[0], "TTLS")
+
 def test_ap_wpa2_eap_ttls_pap_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP - incorrect password"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -798,9 +756,19 @@
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "TTLS", "chap user",
                 anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.der", phase2="auth=CHAP")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    eap_reauth(dev[0], "TTLS")
+
+def test_ap_wpa2_eap_ttls_chap_altsubject_match(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/CHAP"""
+    check_altsubject_match_support(dev[0])
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "chap user",
+                anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=CHAP",
                 altsubject_match="EMAIL:noone@example.com;URI:http://example.com/;DNS:server.w1.fi")
-    hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "TTLS")
 
 def test_ap_wpa2_eap_ttls_chap_incorrect_password(dev, apdev):
@@ -857,7 +825,7 @@
     eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
-                domain_suffix_match="w1.fi")
+                domain_suffix_match="server.w1.fi")
     hwsim_utils.test_connectivity(dev[0], hapd)
     sta1 = hapd.get_sta(dev[0].p2p_interface_addr())
     eapol1 = hapd.get_sta(dev[0].p2p_interface_addr(), info="eapol")
@@ -878,6 +846,31 @@
                 password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
 
+def test_ap_wpa2_eap_ttls_mschapv2_suffix_match(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2"""
+    check_domain_match_full(dev[0])
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                domain_suffix_match="w1.fi")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    eap_reauth(dev[0], "TTLS")
+
+def test_ap_wpa2_eap_ttls_mschapv2_domain_match(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2 (domain_match)"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                domain_match="Server.w1.fi")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    eap_reauth(dev[0], "TTLS")
+
 def test_ap_wpa2_eap_ttls_mschapv2_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2 - incorrect password"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -914,6 +907,48 @@
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "TTLS")
 
+def test_ap_wpa2_eap_ttls_eap_gtc_incorrect_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - incorrect password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "user",
+                anonymous_identity="ttls", password="wrong",
+                ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                expect_failure=True)
+
+def test_ap_wpa2_eap_ttls_eap_gtc_no_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - no password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                expect_failure=True)
+
+def test_ap_wpa2_eap_ttls_eap_gtc_server_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - server OOM"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    with alloc_fail(hapd, 1, "eap_gtc_init"):
+        eap_connect(dev[0], apdev[0], "TTLS", "user",
+                    anonymous_identity="ttls", password="password",
+                    ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                    expect_failure=True)
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(hapd, 1, "eap_gtc_buildReq"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                       eap="TTLS", identity="user",
+                       anonymous_identity="ttls", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                       wait_connect=False, scan_freq="2412")
+        # This would eventually time out, but we can stop after having reached
+        # the allocation failure.
+        for i in range(20):
+            time.sleep(0.1)
+            if hapd.request("GET_ALLOC_FAIL").startswith('0'):
+                break
+
 def test_ap_wpa2_eap_ttls_eap_md5(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -924,6 +959,48 @@
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "TTLS")
 
+def test_ap_wpa2_eap_ttls_eap_md5_incorrect_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - incorrect password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "user",
+                anonymous_identity="ttls", password="wrong",
+                ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
+                expect_failure=True)
+
+def test_ap_wpa2_eap_ttls_eap_md5_no_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - no password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
+                expect_failure=True)
+
+def test_ap_wpa2_eap_ttls_eap_md5_server_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - server OOM"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    with alloc_fail(hapd, 1, "eap_md5_init"):
+        eap_connect(dev[0], apdev[0], "TTLS", "user",
+                    anonymous_identity="ttls", password="password",
+                    ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
+                    expect_failure=True)
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(hapd, 1, "eap_md5_buildReq"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                       eap="TTLS", identity="user",
+                       anonymous_identity="ttls", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
+                       wait_connect=False, scan_freq="2412")
+        # This would eventually time out, but we can stop after having reached
+        # the allocation failure.
+        for i in range(20):
+            time.sleep(0.1)
+            if hapd.request("GET_ALLOC_FAIL").startswith('0'):
+                break
+
 def test_ap_wpa2_eap_ttls_eap_mschapv2(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -941,6 +1018,68 @@
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
                 expect_failure=True)
 
+def test_ap_wpa2_eap_ttls_eap_mschapv2_no_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2 - no password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
+                expect_failure=True)
+
+def test_ap_wpa2_eap_ttls_eap_mschapv2_server_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2 - server OOM"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    with alloc_fail(hapd, 1, "eap_mschapv2_init"):
+        eap_connect(dev[0], apdev[0], "TTLS", "user",
+                    anonymous_identity="ttls", password="password",
+                    ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
+                    expect_failure=True)
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(hapd, 1, "eap_mschapv2_build_challenge"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                       eap="TTLS", identity="user",
+                       anonymous_identity="ttls", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
+                       wait_connect=False, scan_freq="2412")
+        # This would eventually time out, but we can stop after having reached
+        # the allocation failure.
+        for i in range(20):
+            time.sleep(0.1)
+            if hapd.request("GET_ALLOC_FAIL").startswith('0'):
+                break
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(hapd, 1, "eap_mschapv2_build_success_req"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                       eap="TTLS", identity="user",
+                       anonymous_identity="ttls", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
+                       wait_connect=False, scan_freq="2412")
+        # This would eventually time out, but we can stop after having reached
+        # the allocation failure.
+        for i in range(20):
+            time.sleep(0.1)
+            if hapd.request("GET_ALLOC_FAIL").startswith('0'):
+                break
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(hapd, 1, "eap_mschapv2_build_failure_req"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                       eap="TTLS", identity="user",
+                       anonymous_identity="ttls", password="wrong",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
+                       wait_connect=False, scan_freq="2412")
+        # This would eventually time out, but we can stop after having reached
+        # the allocation failure.
+        for i in range(20):
+            time.sleep(0.1)
+            if hapd.request("GET_ALLOC_FAIL").startswith('0'):
+                break
+        dev[0].request("REMOVE_NETWORK all")
+
 def test_ap_wpa2_eap_ttls_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-AKA"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -961,6 +1100,7 @@
 
 def test_ap_wpa2_eap_fast_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/EAP-AKA"""
+    check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "FAST", "0232010000000000",
@@ -999,6 +1139,25 @@
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 expect_failure=True)
 
+def test_ap_wpa2_eap_peap_eap_mschapv2_domain(dev, apdev):
+    """WPA2-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2 with domain"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "PEAP", "DOMAIN\user3",
+                anonymous_identity="peap", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    eap_reauth(dev[0], "PEAP")
+
+def test_ap_wpa2_eap_peap_eap_mschapv2_incorrect_password(dev, apdev):
+    """WPA2-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2 - incorrect password"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "PEAP", "user",
+                anonymous_identity="peap", password="wrong",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                expect_failure=True)
+
 def test_ap_wpa2_eap_peap_crypto_binding(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and crypto binding"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1019,6 +1178,17 @@
                 phase1="peapver=0 crypto_binding=0",
                 phase2="auth=MSCHAPV2")
 
+def test_ap_wpa2_eap_peap_crypto_binding_server_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and crypto binding with server OOM"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    with alloc_fail(hapd, 1, "eap_mschapv2_getKey"):
+        eap_connect(dev[0], apdev[0], "PEAP", "user", password="password",
+                    ca_cert="auth_serv/ca.pem",
+                    phase1="peapver=0 crypto_binding=2",
+                    phase2="auth=MSCHAPV2",
+                    expect_failure=True, local_error_report=True)
+
 def test_ap_wpa2_eap_peap_params(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and various parameters"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1080,7 +1250,7 @@
     cert = read_pem("auth_serv/user.pem")
     if "OK" not in dev[0].request("SET blob usercert " + cert.encode("hex")):
         raise Exception("Could not set usercert blob")
-    key = read_pem("auth_serv/user.key")
+    key = read_pem("auth_serv/user.rsa-key")
     if "OK" not in dev[0].request("SET blob userkey " + key.encode("hex")):
         raise Exception("Could not set cacert blob")
     eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="blob://cacert",
@@ -1196,6 +1366,7 @@
                         only_add_network=True, scan_freq="2412")
 
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].dump_monitor()
     dev[0].select_network(id, freq="2412")
 
@@ -1222,6 +1393,7 @@
                         only_add_network=True, scan_freq="2412")
 
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].dump_monitor()
     dev[0].select_network(id, freq="2412")
 
@@ -1243,6 +1415,7 @@
                         ca_cert="auth_serv/ca.pem",
                         wait_connect=True, scan_freq="2412")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].dump_monitor()
     dev[0].set_network_quoted(id, "ca_cert", "auth_serv/ca-incorrect.pem")
     dev[0].select_network(id, freq="2412")
@@ -1308,6 +1481,59 @@
     if ev is None:
         raise Exception("Network block disabling not reported")
 
+def test_ap_wpa2_eap_tls_neg_domain_match(dev, apdev):
+    """WPA2-Enterprise negative test - domain mismatch"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
+                   password="password", phase2="auth=MSCHAPV2",
+                   ca_cert="auth_serv/ca.pem",
+                   domain_match="w1.fi",
+                   wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    if ev is None:
+        raise Exception("Association and EAP start timed out")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=10)
+    if ev is None:
+        raise Exception("EAP method selection timed out")
+    if "TTLS" not in ev:
+        raise Exception("Unexpected EAP method")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR",
+                            "CTRL-EVENT-EAP-SUCCESS",
+                            "CTRL-EVENT-EAP-FAILURE",
+                            "CTRL-EVENT-CONNECTED",
+                            "CTRL-EVENT-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("EAP result timed out")
+    if "CTRL-EVENT-EAP-TLS-CERT-ERROR" not in ev:
+        raise Exception("TLS certificate error not reported")
+    if "Domain mismatch" not in ev:
+        raise Exception("Domain mismatch not reported")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS",
+                            "CTRL-EVENT-EAP-FAILURE",
+                            "CTRL-EVENT-CONNECTED",
+                            "CTRL-EVENT-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("EAP result(2) timed out")
+    if "CTRL-EVENT-EAP-FAILURE" not in ev:
+        raise Exception("EAP failure not reported")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+                            "CTRL-EVENT-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("EAP result(3) timed out")
+    if "CTRL-EVENT-DISCONNECTED" not in ev:
+        raise Exception("Disconnection not reported")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
+    if ev is None:
+        raise Exception("Network block disabling not reported")
+
 def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev):
     """WPA2-Enterprise negative test - subject mismatch"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1323,9 +1549,16 @@
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
+                            "EAP: Failed to initialize EAP method"], timeout=10)
     if ev is None:
         raise Exception("EAP method selection timed out")
+    if "EAP: Failed to initialize EAP method" in ev:
+        tls = dev[0].request("GET tls_library")
+        if tls.startswith("OpenSSL"):
+            raise Exception("Failed to select EAP method")
+        logger.info("subject_match not supported - connection failed, so test succeeded")
+        return
     if "TTLS" not in ev:
         raise Exception("Unexpected EAP method")
 
@@ -1365,20 +1598,36 @@
     """WPA2-Enterprise negative test - altsubject mismatch"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
+
+    tests = [ "incorrect.example.com",
+              "DNS:incorrect.example.com",
+              "DNS:w1.fi",
+              "DNS:erver.w1.fi" ]
+    for match in tests:
+        _test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev, match)
+
+def _test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev, match):
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
                    password="password", phase2="auth=MSCHAPV2",
                    ca_cert="auth_serv/ca.pem",
-                   altsubject_match="incorrect.example.com",
+                   altsubject_match=match,
                    wait_connect=False, scan_freq="2412")
 
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
+                            "EAP: Failed to initialize EAP method"], timeout=10)
     if ev is None:
         raise Exception("EAP method selection timed out")
+    if "EAP: Failed to initialize EAP method" in ev:
+        tls = dev[0].request("GET tls_library")
+        if tls.startswith("OpenSSL"):
+            raise Exception("Failed to select EAP method")
+        logger.info("altsubject_match not supported - connection failed, so test succeeded")
+        return
     if "TTLS" not in ev:
         raise Exception("Unexpected EAP method")
 
@@ -1414,6 +1663,8 @@
     if ev is None:
         raise Exception("Network block disabling not reported")
 
+    dev[0].request("REMOVE_NETWORK all")
+
 def test_ap_wpa2_eap_unauth_tls(dev, apdev):
     """WPA2-Enterprise connection using UNAUTH-TLS"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1424,6 +1675,7 @@
 
 def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and server certificate hash"""
+    check_cert_probe_support(dev[0])
     srv_cert_hash = "1477c9cd88391609444b83eca45c4f9f324e3051c5c31fc233ac6aede30ce7cd"
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
@@ -1496,6 +1748,7 @@
 
 def test_ap_wpa2_eap_pwd(dev, apdev):
     """WPA2-Enterprise connection using EAP-pwd"""
+    check_eap_capa(dev[0], "PWD")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "PWD", "pwd user", password="secret password")
@@ -1516,8 +1769,21 @@
                 password="secret password",
                 fragment_size="31")
 
+def test_ap_wpa2_eap_pwd_nthash(dev, apdev):
+    """WPA2-Enterprise connection using EAP-pwd and NTHash"""
+    check_eap_capa(dev[0], "PWD")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "PWD", "pwd-hash", password="secret password")
+    eap_connect(dev[1], apdev[0], "PWD", "pwd-hash",
+                password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a")
+    eap_connect(dev[2], apdev[0], "PWD", "pwd user",
+                password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
+                expect_failure=True, local_error_report=True)
+
 def test_ap_wpa2_eap_pwd_groups(dev, apdev):
     """WPA2-Enterprise connection using various EAP-pwd groups"""
+    check_eap_capa(dev[0], "PWD")
     params = { "ssid": "test-wpa2-eap", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf" }
@@ -1529,6 +1795,7 @@
 
 def test_ap_wpa2_eap_pwd_invalid_group(dev, apdev):
     """WPA2-Enterprise connection using invalid EAP-pwd group"""
+    check_eap_capa(dev[0], "PWD")
     params = { "ssid": "test-wpa2-eap", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf" }
@@ -1543,6 +1810,7 @@
 
 def test_ap_wpa2_eap_pwd_as_frag(dev, apdev):
     """WPA2-Enterprise connection using EAP-pwd with server fragmentation"""
+    check_eap_capa(dev[0], "PWD")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params = { "ssid": "test-wpa2-eap", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
@@ -1701,6 +1969,15 @@
     eap_reauth(dev[0], "PEAP", rsn=False)
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-50-f2-1"),
                         ("dot11RSNAAuthenticationSuiteSelected", "00-50-f2-1") ])
+    status = dev[0].get_status(extra="VERBOSE")
+    if 'portControl' not in status:
+        raise Exception("portControl missing from STATUS-VERBOSE")
+    if status['portControl'] != 'Auto':
+        raise Exception("Unexpected portControl value: " + status['portControl'])
+    if 'eap_session_id' not in status:
+        raise Exception("eap_session_id missing from STATUS-VERBOSE")
+    if not status['eap_session_id'].startswith("19"):
+        raise Exception("Unexpected eap_session_id value: " + status['eap_session_id'])
 
 def test_ap_wpa2_eap_interactive(dev, apdev):
     """WPA2-Enterprise connection using interactive identity/password entry"""
@@ -1749,9 +2026,12 @@
     hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "VENDOR-TEST", "vendor-test")
     eap_reauth(dev[0], "VENDOR-TEST")
+    eap_connect(dev[1], apdev[0], "VENDOR-TEST", "vendor-test",
+                password="pending")
 
 def test_ap_wpa2_eap_fast_mschapv2_unauth_prov(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/MSCHAPv2 and unauthenticated provisioning"""
+    check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "FAST", "user",
@@ -1765,6 +2045,7 @@
 
 def test_ap_wpa2_eap_fast_pac_file(dev, apdev, params):
     """WPA2-Enterprise connection using EAP-FAST/MSCHAPv2 and PAC file"""
+    check_eap_capa(dev[0], "FAST")
     pac_file = os.path.join(params['logdir'], "fast.pac")
     pac_file2 = os.path.join(params['logdir'], "fast-bin.pac")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1799,11 +2080,18 @@
                     phase1="fast_pac_format=binary",
                     pac_file=pac_file2)
     finally:
-        subprocess.call(['sudo', 'rm', pac_file])
-        subprocess.call(['sudo', 'rm', pac_file2])
+        try:
+            os.remove(pac_file)
+        except:
+            pass
+        try:
+            os.remove(pac_file2)
+        except:
+            pass
 
 def test_ap_wpa2_eap_fast_binary_pac(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST and binary PAC format"""
+    check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "FAST", "user",
@@ -1817,6 +2105,7 @@
 
 def test_ap_wpa2_eap_fast_missing_pac_config(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST and missing PAC config"""
+    check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hostapd.add_ap(apdev[0]['ifname'], params)
 
@@ -1842,6 +2131,7 @@
 
 def test_ap_wpa2_eap_fast_gtc_auth_prov(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/GTC and authenticated provisioning"""
+    check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "FAST", "user",
@@ -1853,6 +2143,26 @@
     if res['tls_session_reused'] != '1':
         raise Exception("EAP-FAST could not use PAC session ticket")
 
+def test_ap_wpa2_eap_fast_gtc_identity_change(dev, apdev):
+    """WPA2-Enterprise connection using EAP-FAST/GTC and identity changing"""
+    check_eap_capa(dev[0], "FAST")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    id = eap_connect(dev[0], apdev[0], "FAST", "user",
+                     anonymous_identity="FAST", password="password",
+                     ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                     phase1="fast_provisioning=2",
+                     pac_file="blob://fast_pac_auth")
+    dev[0].set_network_quoted(id, "identity", "user2")
+    dev[0].wait_disconnected()
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
+    if ev is None:
+        raise Exception("EAP-FAST not started")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("EAP failure not reported")
+    dev[0].wait_disconnected()
+
 def test_ap_wpa2_eap_tls_ocsp(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and verifying OCSP"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
@@ -1895,7 +2205,78 @@
     if ev is None:
         raise Exception("Timeout on EAP failure report")
 
-def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
+def test_ap_wpa2_eap_ttls_ocsp_revoked(dev, apdev, params):
+    """WPA2-Enterprise connection using EAP-TTLS and OCSP status revoked"""
+    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-revoked.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="pap user", ca_cert="auth_serv/ca.pem",
+                   anonymous_identity="ttls", password="password",
+                   phase2="auth=PAP", ocsp=2,
+                   wait_connect=False, scan_freq="2412")
+    count = 0
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"])
+        if ev is None:
+            raise Exception("Timeout on EAP status")
+        if 'bad certificate status response' in ev:
+            break
+        if 'certificate revoked' in ev:
+            break
+        count = count + 1
+        if count > 10:
+            raise Exception("Unexpected number of EAP status messages")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+
+def test_ap_wpa2_eap_ttls_ocsp_unknown(dev, apdev, params):
+    """WPA2-Enterprise connection using EAP-TTLS and OCSP status revoked"""
+    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-unknown.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="pap user", ca_cert="auth_serv/ca.pem",
+                   anonymous_identity="ttls", password="password",
+                   phase2="auth=PAP", ocsp=2,
+                   wait_connect=False, scan_freq="2412")
+    count = 0
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"])
+        if ev is None:
+            raise Exception("Timeout on EAP status")
+        if 'bad certificate status response' in ev:
+            break
+        count = count + 1
+        if count > 10:
+            raise Exception("Unexpected number of EAP status messages")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+
+def test_ap_wpa2_eap_ttls_optional_ocsp_unknown(dev, apdev, params):
+    """WPA2-Enterprise connection using EAP-TTLS and OCSP status revoked"""
+    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-unknown.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="pap user", ca_cert="auth_serv/ca.pem",
+                   anonymous_identity="ttls", password="password",
+                   phase2="auth=PAP", ocsp=1, scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)"""
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
@@ -1907,6 +2288,27 @@
                    private_key_passwd="whatever",
                    domain_suffix_match="server3.w1.fi",
                    scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev):
+    """WPA2-Enterprise using EAP-TLS and domainmatch (CN)"""
+    params = int_eap_server_params()
+    params["server_cert"] = "auth_serv/server-no-dnsname.pem"
+    params["private_key"] = "auth_serv/server-no-dnsname.key"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever",
+                   domain_match="server3.w1.fi",
+                   scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
+    """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)"""
+    check_domain_match_full(dev[0])
+    params = int_eap_server_params()
+    params["server_cert"] = "auth_serv/server-no-dnsname.pem"
+    params["private_key"] = "auth_serv/server-no-dnsname.key"
+    hostapd.add_ap(apdev[0]['ifname'], params)
     dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -1941,6 +2343,33 @@
     if ev is None:
         raise Exception("Timeout on EAP failure report (2)")
 
+def test_ap_wpa2_eap_tls_domain_mismatch_cn(dev, apdev):
+    """WPA2-Enterprise using EAP-TLS and domain mismatch (CN)"""
+    params = int_eap_server_params()
+    params["server_cert"] = "auth_serv/server-no-dnsname.pem"
+    params["private_key"] = "auth_serv/server-no-dnsname.key"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever",
+                   domain_match="example.com",
+                   wait_connect=False,
+                   scan_freq="2412")
+    dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever",
+                   domain_match="w1.fi",
+                   wait_connect=False,
+                   scan_freq="2412")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+    ev = dev[1].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report (2)")
+
 def test_ap_wpa2_eap_ttls_expired_cert(dev, apdev):
     """WPA2-Enterprise using EAP-TTLS and expired certificate"""
     params = int_eap_server_params()
@@ -2063,9 +2492,7 @@
 
 def test_ap_wpa2_eap_sim_aka_result_ind(dev, apdev):
     """WPA2-Enterprise using EAP-SIM/AKA and protected result indication"""
-    if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return "skip"
+    check_hlr_auc_gw_support()
     params = int_eap_server_params()
     params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
     params['eap_sim_aka_result_ind'] = "1"
@@ -2141,7 +2568,7 @@
     try:
         import sqlite3
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No sqlite3 module available")
     dbfile = os.path.join(params['logdir'], "eap-user.db")
     try:
         os.remove(dbfile)
@@ -2214,6 +2641,9 @@
 
 def test_openssl_cipher_suite_config_wpas(dev, apdev):
     """OpenSSL cipher suite configuration on wpa_supplicant"""
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("TLS library is not OpenSSL: " + tls)
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     eap_connect(dev[0], apdev[0], "TTLS", "pap user",
@@ -2228,9 +2658,15 @@
 
 def test_openssl_cipher_suite_config_hapd(dev, apdev):
     """OpenSSL cipher suite configuration on hostapd"""
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL: " + tls)
     params = int_eap_server_params()
     params['openssl_ciphers'] = "AES256"
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    tls = hapd.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls)
     eap_connect(dev[0], apdev[0], "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
@@ -2243,3 +2679,190 @@
                 anonymous_identity="ttls", password="password",
                 openssl_ciphers="HIGH:!ADH",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+
+def test_wpa2_eap_ttls_pap_key_lifetime_in_memory(dev, apdev, params):
+    """Key lifetime in memory with WPA2-Enterprise using EAP-TTLS/PAP"""
+    p = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
+    pid = find_wpas_process(dev[0])
+    id = eap_connect(dev[0], apdev[0], "TTLS", "pap-secret",
+                     anonymous_identity="ttls", password=password,
+                     ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+    time.sleep(1)
+    buf = read_process_memory(pid, password)
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    dev[0].relog()
+    msk = None
+    emsk = None
+    pmk = None
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "EAP-TTLS: Derived key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                msk = binascii.unhexlify(val)
+            if "EAP-TTLS: Derived EMSK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                emsk = binascii.unhexlify(val)
+            if "WPA: PMK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmk = binascii.unhexlify(val)
+            if "WPA: PTK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                ptk = binascii.unhexlify(val)
+            if "WPA: Group Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not msk or not emsk or not pmk or not ptk or not gtk:
+        raise Exception("Could not find keys from debug log")
+    if len(gtk) != 16:
+        raise Exception("Unexpected GTK length")
+
+    kck = ptk[0:16]
+    kek = ptk[16:32]
+    tk = ptk[32:48]
+
+    fname = os.path.join(params['logdir'],
+                         'wpa2_eap_ttls_pap_key_lifetime_in_memory.memctx-')
+
+    logger.info("Checking keys in memory while associated")
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    if password not in buf:
+        raise HwsimSkip("Password not found while associated")
+    if pmk not in buf:
+        raise HwsimSkip("PMK not found while associated")
+    if kck not in buf:
+        raise Exception("KCK not found while associated")
+    if kek not in buf:
+        raise Exception("KEK not found while associated")
+    if tk in buf:
+        raise Exception("TK found from memory")
+    if gtk in buf:
+        raise Exception("GTK found from memory")
+
+    logger.info("Checking keys in memory after disassociation")
+    buf = read_process_memory(pid, password)
+
+    # Note: Password is still present in network configuration
+    # Note: PMK is in PMKSA cache and EAP fast re-auth data
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+    dev[0].request("PMKSA_FLUSH")
+    dev[0].set_network_quoted(id, "identity", "foo")
+    logger.info("Checking keys in memory after PMKSA cache and EAP fast reauth flush")
+    buf = read_process_memory(pid, password)
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    verify_not_present(buf, pmk, fname, "PMK")
+
+    dev[0].request("REMOVE_NETWORK all")
+
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, password)
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    verify_not_present(buf, password, fname, "password")
+    verify_not_present(buf, pmk, fname, "PMK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+    verify_not_present(buf, msk, fname, "MSK")
+    verify_not_present(buf, emsk, fname, "EMSK")
+
+def test_ap_wpa2_eap_unexpected_wep_eapol_key(dev, apdev):
+    """WPA2-Enterprise connection and unexpected WEP EAPOL-Key"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+
+    # Send unexpected WEP EAPOL-Key; this gets dropped
+    res = dev[0].request("EAPOL_RX " + bssid + " 0203002c0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+def test_ap_wpa2_eap_in_bridge(dev, apdev):
+    """WPA2-EAP and wpas interface in a bridge"""
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    try:
+        _test_ap_wpa2_eap_in_bridge(dev, apdev)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
+        subprocess.call(['brctl', 'delif', br_ifname, ifname])
+        subprocess.call(['brctl', 'delbr', br_ifname])
+        subprocess.call(['iw', ifname, 'set', '4addr', 'off'])
+
+def _test_ap_wpa2_eap_in_bridge(dev, apdev):
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    subprocess.call(['brctl', 'addbr', br_ifname])
+    subprocess.call(['brctl', 'setfd', br_ifname, '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
+    subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
+    subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
+    wpas.interface_add(ifname, br_ifname=br_ifname)
+
+    id = eap_connect(wpas, apdev[0], "PAX", "pax.user@example.com",
+                     password_hex="0123456789abcdef0123456789abcdef")
+    eap_reauth(wpas, "PAX")
+    # Try again as a regression test for packet socket workaround
+    eap_reauth(wpas, "PAX")
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.request("RECONNECT")
+    wpas.wait_connected()
+
+def test_ap_wpa2_eap_session_ticket(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS and TLS session ticket enabled"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    key_mgmt = hapd.get_config()['key_mgmt']
+    if key_mgmt.split(' ')[0] != "WPA-EAP":
+        raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
+    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem",
+                phase1="tls_disable_session_ticket=0", phase2="auth=PAP")
+    eap_reauth(dev[0], "TTLS")
+
+def test_ap_wpa2_eap_no_workaround(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS and eap_workaround=0"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    key_mgmt = hapd.get_config()['key_mgmt']
+    if key_mgmt.split(' ')[0] != "WPA-EAP":
+        raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
+    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+                anonymous_identity="ttls", password="password",
+                ca_cert="auth_serv/ca.pem", eap_workaround='0',
+                phase2="auth=PAP")
+    eap_reauth(dev[0], "TTLS")
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
index fe0c6bb..184a8d7 100644
--- a/tests/hwsim/test_ap_ft.py
+++ b/tests/hwsim/test_ap_ft.py
@@ -4,6 +4,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import binascii
+import os
 import time
 import subprocess
 import logging
@@ -11,8 +13,9 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
 from wlantest import Wlantest
-from test_ap_psk import check_mib
+from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations
 
 def ft_base_rsn():
     params = { "wpa": "2",
@@ -234,6 +237,106 @@
                    scan_freq="2412")
     dev[0].roam_over_ds("02:11:22:33:44:55", fail_test=True)
 
+def test_ap_ft_over_ds_unexpected(dev, apdev):
+    """WPA2-PSK-FT AP over DS and unexpected response"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    params = ft_params2(ssid=ssid, passphrase=passphrase)
+    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+
+    dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
+                   scan_freq="2412")
+    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+        ap1 = apdev[0]
+        ap2 = apdev[1]
+        hapd1ap = hapd0
+        hapd2ap = hapd1
+    else:
+        ap1 = apdev[1]
+        ap2 = apdev[0]
+        hapd1ap = hapd1
+        hapd2ap = hapd0
+
+    addr = dev[0].own_addr()
+    hapd1ap.set("ext_mgmt_frame_handling", "1")
+    logger.info("Foreign STA address")
+    msg = {}
+    msg['fc'] = 13 << 4
+    msg['da'] = addr
+    msg['sa'] = ap1['bssid']
+    msg['bssid'] = ap1['bssid']
+    msg['payload'] = binascii.unhexlify("06021122334455660102030405060000")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No over-the-DS in progress")
+    msg['payload'] = binascii.unhexlify("0602" + addr.replace(':', '') + "0102030405060000")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("Non-zero status code")
+    msg['payload'] = binascii.unhexlify("0602" + addr.replace(':', '') + "0102030405060100")
+    hapd1ap.mgmt_tx(msg)
+
+    hapd1ap.dump_monitor()
+
+    dev[0].scan_for_bss(ap2['bssid'], freq="2412")
+    if "OK" not in dev[0].request("FT_DS " + ap2['bssid']):
+            raise Exception("FT_DS failed")
+
+    req = hapd1ap.mgmt_rx()
+
+    logger.info("Foreign Target AP")
+    msg['payload'] = binascii.unhexlify("0602" + addr.replace(':', '') + "0102030405060000")
+    hapd1ap.mgmt_tx(msg)
+
+    addrs = addr.replace(':', '') + ap2['bssid'].replace(':', '')
+
+    logger.info("No IEs")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "0000")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("Invalid IEs (trigger parsing failure)")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003700")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("Too short MDIE")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "000036021122")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("Mobility domain mismatch")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603112201")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No FTIE")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b201")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("FTIE SNonce mismatch")
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b201375e0000" + "00000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "1000000000000000000000000000000000000000000000000000000000000001" + "030a6e6173322e77312e6669")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No R0KH-ID subelem in FTIE")
+    snonce = binascii.hexlify(req['payload'][111:111+32])
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b20137520000" + "00000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + snonce)
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No R0KH-ID subelem mismatch in FTIE")
+    snonce = binascii.hexlify(req['payload'][111:111+32])
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b201375e0000" + "00000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + snonce + "030a11223344556677889900")
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No R1KH-ID subelem in FTIE")
+    r0khid = binascii.hexlify(req['payload'][145:145+10])
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b201375e0000" + "00000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + snonce + "030a" + r0khid)
+    hapd1ap.mgmt_tx(msg)
+
+    logger.info("No RSNE")
+    r0khid = binascii.hexlify(req['payload'][145:145+10])
+    msg['payload'] = binascii.unhexlify("0602" + addrs + "00003603a1b20137660000" + "00000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + snonce + "030a" + r0khid + "0106000102030405")
+    hapd1ap.mgmt_tx(msg)
+
 def test_ap_ft_pmf_over_ds(dev, apdev):
     """WPA2-PSK-FT AP over DS with PMF"""
     ssid = "test-ft"
@@ -264,6 +367,8 @@
 
 def test_ap_ft_sae(dev, apdev):
     """WPA2-PSK-FT-SAE AP"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     ssid = "test-ft"
     passphrase="12345678"
 
@@ -282,6 +387,8 @@
 
 def test_ap_ft_sae_over_ds(dev, apdev):
     """WPA2-PSK-FT-SAE AP over DS"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     ssid = "test-ft"
     passphrase="12345678"
 
@@ -456,3 +563,107 @@
     if ev is None:
         raise Exception("GTK rekey timed out after FT protocol")
     hwsim_utils.test_connectivity(dev[0], hapd1)
+
+def test_ft_psk_key_lifetime_in_memory(dev, apdev, params):
+    """WPA2-PSK-FT and key lifetime in memory"""
+    ssid = "test-ft"
+    passphrase="04c2726b4b8d5f1b4db9c07aa4d9e9d8f765cb5d25ec817e6cc4fcdd5255db0"
+    psk = '93c90846ff67af9037ed83fb72b63dbeddaa81d47f926c20909b5886f1d9358d'
+    pmk = binascii.unhexlify(psk)
+    p = ft_params1(ssid=ssid, passphrase=passphrase)
+    hapd0 = hostapd.add_ap(apdev[0]['ifname'], p)
+    p = ft_params2(ssid=ssid, passphrase=passphrase)
+    hapd1 = hostapd.add_ap(apdev[1]['ifname'], p)
+
+    pid = find_wpas_process(dev[0])
+
+    dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
+                   scan_freq="2412")
+    time.sleep(1)
+
+    buf = read_process_memory(pid, pmk)
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    dev[0].relog()
+    pmkr0 = None
+    pmkr1 = None
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "FT: PMK-R0 - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmkr0 = binascii.unhexlify(val)
+            if "FT: PMK-R1 - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmkr1 = binascii.unhexlify(val)
+            if "FT: KCK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                kck = binascii.unhexlify(val)
+            if "FT: KEK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                kek = binascii.unhexlify(val)
+            if "FT: TK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                tk = binascii.unhexlify(val)
+            if "WPA: Group Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not pmkr0 or not pmkr1 or not kck or not kek or not tk or not gtk:
+        raise Exception("Could not find keys from debug log")
+    if len(gtk) != 16:
+        raise Exception("Unexpected GTK length")
+
+    logger.info("Checking keys in memory while associated")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, pmkr0, "PMK-R0")
+    get_key_locations(buf, pmkr1, "PMK-R1")
+    if pmk not in buf:
+        raise HwsimSkip("PMK not found while associated")
+    if pmkr0 not in buf:
+        raise HwsimSkip("PMK-R0 not found while associated")
+    if pmkr1 not in buf:
+        raise HwsimSkip("PMK-R1 not found while associated")
+    if kck not in buf:
+        raise Exception("KCK not found while associated")
+    if kek not in buf:
+        raise Exception("KEK not found while associated")
+    if tk in buf:
+        raise Exception("TK found from memory")
+    if gtk in buf:
+        raise Exception("GTK found from memory")
+
+    logger.info("Checking keys in memory after disassociation")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, pmkr0, "PMK-R0")
+    get_key_locations(buf, pmkr1, "PMK-R1")
+
+    # Note: PMK/PSK is still present in network configuration
+
+    fname = os.path.join(params['logdir'],
+                         'ft_psk_key_lifetime_in_memory.memctx-')
+    verify_not_present(buf, pmkr0, fname, "PMK-R0")
+    verify_not_present(buf, pmkr1, fname, "PMK-R1")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+    dev[0].request("REMOVE_NETWORK all")
+
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, pmkr0, "PMK-R0")
+    get_key_locations(buf, pmkr1, "PMK-R1")
+
+    verify_not_present(buf, pmk, fname, "PMK")
+    verify_not_present(buf, pmkr0, fname, "PMK-R0")
+    verify_not_present(buf, pmkr1, fname, "PMK-R1")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py
index 804e9d0..90f630c 100644
--- a/tests/hwsim/test_ap_hs20.py
+++ b/tests/hwsim/test_ap_hs20.py
@@ -1,5 +1,5 @@
 # Hotspot 2.0 tests
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -16,9 +16,12 @@
 import subprocess
 
 import hostapd
+from utils import HwsimSkip
 import hwsim_utils
+from tshark import run_tshark
 from wlantest import Wlantest
 from wpasupplicant import WpaSupplicant
+from test_ap_eap import check_eap_capa, check_domain_match_full
 
 def hs20_ap_params(ssid="test-hs20"):
     params = hostapd.wpa2_params(ssid=ssid)
@@ -56,12 +59,13 @@
     if bssid not in ev:
         raise Exception("Connected to incorrect network")
     dev.request("REMOVE_NETWORK all")
+    dev.wait_disconnected()
 
 def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
     dev.dump_monitor()
     if bssid and freq and not no_match:
         dev.scan_for_bss(bssid, freq=freq)
-    freq_extra = " freq=" + freq if freq else ""
+    freq_extra = " freq=" + str(freq) if freq else ""
     dev.request("INTERWORKING_SELECT" + freq_extra)
     ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
                         timeout=15)
@@ -95,12 +99,9 @@
 
 def hlr_auc_gw_available():
     if not os.path.exists("/tmp/hlr_auc_gw.sock"):
-        logger.info("No hlr_auc_gw available");
-        return False
+        raise HwsimSkip("No hlr_auc_gw socket available")
     if not os.path.exists("../../hostapd/hlr_auc_gw"):
-        logger.info("No hlr_auc_gw available");
-        return False
-    return True
+        raise HwsimSkip("No hlr_auc_gw available")
 
 def interworking_ext_sim_connect(dev, bssid, method):
     dev.request("INTERWORKING_CONNECT " + bssid)
@@ -159,6 +160,8 @@
 
 def test_ap_anqp_sharing(dev, apdev):
     """ANQP sharing within ESS and explicit unshare"""
+    dev[0].flush_scan_cache()
+
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
@@ -180,8 +183,13 @@
     interworking_select(dev[0], None, "home", freq="2412")
     dev[0].dump_monitor()
 
+    logger.debug("BSS entries:\n" + dev[0].request("BSS RANGE=ALL"))
     res1 = dev[0].get_bss(bssid)
     res2 = dev[0].get_bss(bssid2)
+    if 'anqp_nai_realm' not in res1:
+        raise Exception("anqp_nai_realm not found for AP1")
+    if 'anqp_nai_realm' not in res2:
+        raise Exception("anqp_nai_realm not found for AP2")
     if res1['anqp_nai_realm'] != res2['anqp_nai_realm']:
         raise Exception("ANQP results were not shared between BSSes")
 
@@ -275,7 +283,7 @@
 def test_ap_interworking_scan_filtering(dev, apdev):
     """Interworking scan filtering with HESSID and access network type"""
     try:
-        return _test_ap_interworking_scan_filtering(dev, apdev)
+        _test_ap_interworking_scan_filtering(dev, apdev)
     finally:
         dev[0].request("SET hessid 00:00:00:00:00:00")
         dev[0].request("SET access_network_type 15")
@@ -411,8 +419,7 @@
 
 def test_ap_hs20_sim(dev, apdev):
     """Hotspot 2.0 with simulated SIM and EAP-SIM"""
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     hs20_simulated_sim(dev[0], apdev[0], "SIM")
     dev[0].request("INTERWORKING_SELECT auto freq=2412")
     ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
@@ -421,20 +428,17 @@
 
 def test_ap_hs20_aka(dev, apdev):
     """Hotspot 2.0 with simulated USIM and EAP-AKA"""
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     hs20_simulated_sim(dev[0], apdev[0], "AKA")
 
 def test_ap_hs20_aka_prime(dev, apdev):
     """Hotspot 2.0 with simulated USIM and EAP-AKA'"""
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     hs20_simulated_sim(dev[0], apdev[0], "AKA'")
 
 def test_ap_hs20_ext_sim(dev, apdev):
     """Hotspot 2.0 with external SIM processing"""
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
@@ -454,8 +458,7 @@
 
 def test_ap_hs20_ext_sim_roaming(dev, apdev):
     """Hotspot 2.0 with external SIM processing in roaming network"""
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
@@ -553,6 +556,45 @@
     if status['hs20'] != "2":
         raise Exception("Unexpected HS 2.0 support indication")
 
+def test_ap_hs20_auto_interworking_no_match(dev, apdev):
+    """Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "mismatch" })
+
+    dev[0].hs20_enable(auto_interworking=True)
+    id = dev[0].connect("mismatch", psk="12345678", scan_freq="2412",
+                        only_add_network=True)
+    dev[0].request("ENABLE_NETWORK " + str(id) + " no-connect")
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'domain': "example.com",
+                                  'update_identifier': "1234" })
+    dev[0].request("INTERWORKING_SELECT auto freq=2412")
+    time.sleep(0.1)
+    dev[0].dump_monitor()
+    for i in range(5):
+        logger.info("start ping")
+        if "PONG" not in dev[0].ctrl.request("PING", timeout=2):
+            raise Exception("PING failed")
+        logger.info("ping done")
+        fetch = 0
+        scan = 0
+        for j in range(15):
+            ev = dev[0].wait_event([ "ANQP fetch completed",
+                                     "CTRL-EVENT-SCAN-RESULTS" ], timeout=0.05)
+            if ev is None:
+                break
+            if "ANQP fetch completed" in ev:
+                fetch += 1
+            else:
+                scan += 1
+        if fetch > 2 * scan + 3:
+            raise Exception("Too many ANQP fetch iterations")
+        dev[0].dump_monitor()
+    dev[0].request("DISCONNECT")
+
 def test_ap_hs20_auto_interworking_no_cred_match(dev, apdev):
     """Hotspot 2.0 connection with auto_interworking=1 but no cred match"""
     bssid = apdev[0]['bssid']
@@ -583,6 +625,7 @@
 
     dev.hs20_enable()
     dev.add_cred_values({ 'realm': "example.com",
+                          'ca_cert': "auth_serv/ca.pem",
                           'username': user,
                           'password': "password" })
     interworking_select(dev, bssid, freq="2412")
@@ -669,10 +712,12 @@
 
 def test_ap_hs20_eap_fast_mschapv2(dev, apdev):
     """Hotspot 2.0 connection with FAST/EAP-MSCHAPV2"""
+    check_eap_capa(dev[0], "FAST")
     eap_test(dev[0], apdev[0], "43[3:26]", "FAST", "user")
 
 def test_ap_hs20_eap_fast_gtc(dev, apdev):
     """Hotspot 2.0 connection with FAST/EAP-GTC"""
+    check_eap_capa(dev[0], "FAST")
     eap_test(dev[0], apdev[0], "43[3:6]", "FAST", "user")
 
 def test_ap_hs20_eap_tls(dev, apdev):
@@ -743,6 +788,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "pap user",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -762,6 +808,7 @@
         id = dev[0].add_cred_values({ 'username': "user",
                                       'password': "password",
                                       'domain': "example.com",
+                                      'ca_cert': "auth_serv/ca.pem",
                                       'roaming_consortium': consortium,
                                       'eap': "PEAP" })
         interworking_select(dev[0], bssid, "home", freq="2412")
@@ -788,6 +835,7 @@
     id = dev[0].add_cred_values({ 'realm': "roaming.example.com",
                                   'username': "hs20-test",
                                   'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'domain': "example.com" })
     interworking_select(dev[0], bssid, "roaming", freq="2412")
     interworking_connect(dev[0], bssid, "TTLS")
@@ -802,6 +850,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password" })
     interworking_select(dev[0], bssid, "unknown", freq="2412")
@@ -818,6 +867,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -834,6 +884,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -869,6 +920,7 @@
     dev[0].hs20_enable()
     dev[0].request("SET pmf 2")
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -893,6 +945,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -915,6 +968,7 @@
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
+               'ca_cert': "auth_serv/ca.pem",
                'username': "hs20-test",
                'password': "password",
                'domain': "example.com" }
@@ -954,6 +1008,7 @@
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
+               'ca_cert': "auth_serv/ca.pem",
                'username': "hs20-test",
                'password': "password",
                'domain': "example.com" }
@@ -1032,9 +1087,10 @@
     dev.dump_monitor()
     return events
 
-def default_cred(domain=None):
+def default_cred(domain=None, user="hs20-test"):
     cred = { 'realm': "example.com",
-             'username': "hs20-test",
+             'ca_cert': "auth_serv/ca.pem",
+             'username': user,
              'password': "password" }
     if domain:
         cred['domain'] = domain
@@ -1133,6 +1189,7 @@
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'username': "hs20-test",
                                   'password': "password",
                                   'domain': "example.com" })
@@ -1161,7 +1218,7 @@
     if bssid2 not in ev:
         raise Exception("Unexpected BSSID after reconnection")
 
-def test_ap_hs20_domain_suffix_match(dev, apdev):
+def test_ap_hs20_domain_suffix_match_full(dev, apdev):
     """Hotspot 2.0 and domain_suffix_match"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
@@ -1171,8 +1228,9 @@
     id = dev[0].add_cred_values({ 'realm': "example.com",
                                   'username': "hs20-test",
                                   'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
                                   'domain': "example.com",
-                                  'domain_suffix_match': "w1.fi" })
+                                  'domain_suffix_match': "server.w1.fi" })
     interworking_select(dev[0], bssid, "home", freq="2412")
     dev[0].dump_monitor()
     interworking_connect(dev[0], bssid, "TTLS")
@@ -1189,6 +1247,24 @@
     if "Domain suffix mismatch" not in ev:
         raise Exception("Domain suffix mismatch not reported")
 
+def test_ap_hs20_domain_suffix_match(dev, apdev):
+    """Hotspot 2.0 and domain_suffix_match"""
+    check_domain_match_full(dev[0])
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'domain': "example.com",
+                                  'domain_suffix_match': "w1.fi" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
+    dev[0].dump_monitor()
+    interworking_connect(dev[0], bssid, "TTLS")
+
 def test_ap_hs20_roaming_partner_preference(dev, apdev):
     """Hotspot 2.0 and roaming partner preference"""
     params = hs20_ap_params()
@@ -1274,13 +1350,12 @@
 def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
     """Hotspot 2.0 multi-cred sp_priority"""
     try:
-        return _test_ap_hs20_multi_cred_sp_prio(dev, apdev)
+        _test_ap_hs20_multi_cred_sp_prio(dev, apdev)
     finally:
         dev[0].request("SET external_sim 0")
 
 def _test_ap_hs20_multi_cred_sp_prio(dev, apdev):
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
@@ -1295,6 +1370,7 @@
                                    'provisioning_sp': "example.com",
                                    'sp_priority' :"1" })
     id2 = dev[0].add_cred_values({ 'realm': "example.com",
+                                   'ca_cert': "auth_serv/ca.pem",
                                    'username': "hs20-test",
                                    'password': "password",
                                    'domain': "example.com",
@@ -1317,13 +1393,12 @@
 def test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
     """Hotspot 2.0 multi-cred sp_priority with two BSSes"""
     try:
-        return _test_ap_hs20_multi_cred_sp_prio2(dev, apdev)
+        _test_ap_hs20_multi_cred_sp_prio2(dev, apdev)
     finally:
         dev[0].request("SET external_sim 0")
 
 def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
-    if not hlr_auc_gw_available():
-        return "skip"
+    hlr_auc_gw_available()
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
@@ -1346,6 +1421,7 @@
                                    'provisioning_sp': "example.com",
                                    'sp_priority': "1" })
     id2 = dev[0].add_cred_values({ 'realm': "example.com",
+                                   'ca_cert': "auth_serv/ca.pem",
                                    'username': "hs20-test",
                                    'password': "password",
                                    'domain': "example.com",
@@ -1475,6 +1551,7 @@
     ev = dev.wait_event(["INTERWORKING-AP"])
     if ev is None:
         raise Exception("Network selection timed out");
+    logger.debug("BSS entries:\n" + dev.request("BSS RANGE=ALL"))
     if "type=" + type not in ev:
         raise Exception("Unexpected network type")
     if below and "below_min_backhaul=1" not in ev:
@@ -1529,6 +1606,52 @@
 
     check_auto_select(dev[0], bssid2)
 
+def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
+    """Hotspot 2.0 network selection with min bandwidth (home) while hidden SSID is included in scan results"""
+    bssid = apdev[0]['bssid']
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret',
+                                                "ignore_broadcast_ssid": "1" })
+    dev[0].scan_for_bss(bssid, freq=2412)
+    hapd.disable()
+    hapd_global = hostapd.HostapdGlobal()
+    hapd_global.flush()
+    hapd_global.remove(apdev[0]['ifname'])
+
+    params = hs20_ap_params()
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
+    id = dev[0].add_cred_values(values)
+    check_bandwidth_selection(dev[0], "home", False)
+    dev[0].remove_cred(id)
+
+    values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
+    id = dev[0].add_cred_values(values)
+    check_bandwidth_selection(dev[0], "home", True)
+    dev[0].remove_cred(id)
+
+    values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
+    id = dev[0].add_cred_values(values)
+    check_bandwidth_selection(dev[0], "home", True)
+    dev[0].remove_cred(id)
+
+    values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
+    id = dev[0].add_cred_values(values)
+    check_bandwidth_selection(dev[0], "home", True)
+    check_auto_select(dev[0], bssid)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params(ssid="test-hs20-b")
+    params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
+    hostapd.add_ap(apdev[1]['ifname'], params)
+
+    check_auto_select(dev[0], bssid2)
+
+    dev[0].flush_scan_cache()
+
 def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
     """Hotspot 2.0 network selection with min bandwidth (roaming)"""
     bssid = apdev[0]['bssid']
@@ -1725,7 +1848,7 @@
 
 def _test_ap_hs20_remediation_required_ctrl(dev, apdev):
     bssid = apdev[0]['bssid']
-    addr = dev[0].p2p_dev_addr()
+    addr = dev[0].own_addr()
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
@@ -1802,11 +1925,20 @@
                    wait_connect=False)
     dev[2].connect("osen", key_mgmt="NONE", wep_key0='"hello"',
                    scan_freq="2412", wait_connect=False)
+    dev[0].flush_scan_cache()
     dev[0].connect("osen", proto="OSEN", key_mgmt="OSEN", pairwise="CCMP",
                    group="GTK_NOT_USED",
                    eap="WFA-UNAUTH-TLS", identity="osen@example.com",
                    ca_cert="auth_serv/ca.pem",
                    scan_freq="2412")
+    res = dev[0].get_bss(apdev[0]['bssid'])['flags']
+    if "[OSEN-OSEN-CCMP]" not in res:
+        raise Exception("OSEN not reported in BSS")
+    if "[WEP]" in res:
+        raise Exception("WEP reported in BSS")
+    res = dev[0].request("SCAN_RESULTS")
+    if "[OSEN-OSEN-CCMP]" not in res:
+        raise Exception("OSEN not reported in SCAN_RESULTS")
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
@@ -1979,6 +2111,25 @@
     if bssid2 not in ev:
         raise Exception("Unexpected network selected")
 
+def test_ap_hs20_interworking_select_blocking_scan(dev, apdev):
+    """Ongoing INTERWORKING_SELECT blocking SCAN"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].hs20_enable()
+    values = { 'realm': "example.com",
+               'username': "hs20-test",
+               'password': "password",
+               'domain': "example.com" }
+    dev[0].add_cred_values(values)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("INTERWORKING_SELECT auto freq=2412")
+    if "FAIL-BUSY" not in dev[0].request("SCAN"):
+        raise Exception("Unexpected SCAN command result")
+    dev[0].wait_connected(timeout=15)
+
 def test_ap_hs20_fetch_osu(dev, apdev):
     """Hotspot 2.0 OSU provider and icon fetch"""
     bssid = apdev[0]['bssid']
@@ -2042,10 +2193,11 @@
 
         with open(dir + "/osu-providers.txt", "r") as f:
             prov = f.read()
+            logger.debug("osu-providers.txt: " + prov)
         if "OSU-PROVIDER " + bssid not in prov:
-            raise Exception("Missing OSU_PROVIDER")
+            raise Exception("Missing OSU_PROVIDER(1)")
         if "OSU-PROVIDER " + bssid2 not in prov:
-            raise Exception("Missing OSU_PROVIDER")
+            raise Exception("Missing OSU_PROVIDER(2)")
     finally:
         files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
         for f in files:
@@ -2180,7 +2332,7 @@
     try:
         import sqlite3
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No sqlite3 module available")
     dbfile = os.path.join(params['logdir'], "eap-user.db")
     try:
         os.remove(dbfile)
@@ -2324,6 +2476,20 @@
         raise Exception("Unexpected number of networks after to remove_crec")
     dev[0].wait_disconnected(timeout=10)
 
+def test_ap_hs20_interworking_add_network(dev, apdev):
+    """Hotspot 2.0 connection using INTERWORKING_ADD_NETWORK"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['nai_realm'] = [ "0,example.com,21[3:26][6:7][99:99]" ]
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].hs20_enable()
+    dev[0].add_cred_values(default_cred(user="user"))
+    interworking_select(dev[0], bssid, freq=2412)
+    id = dev[0].interworking_add_network(bssid)
+    dev[0].select_network(id, freq=2412)
+    dev[0].wait_connected()
+
 def _test_ap_hs20_proxyarp(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
@@ -2342,8 +2508,7 @@
         hapd.enable()
     except:
         # For now, do not report failures due to missing kernel support
-        logger.info("Could not start hostapd - assume proxyarp not supported in kernel version")
-        return "skip"
+        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
     if ev is None:
         raise Exception("AP startup timed out")
@@ -2411,19 +2576,48 @@
     if len(matches) > 0:
         raise Exception("Unexpected neighbor entries after disconnect")
 
+def test_ap_hs20_hidden_ssid_in_scan_res(dev, apdev):
+    """Hotspot 2.0 connection with hidden SSId in scan results"""
+    bssid = apdev[0]['bssid']
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret',
+                                                "ignore_broadcast_ssid": "1" })
+    dev[0].scan_for_bss(bssid, freq=2412)
+    hapd.disable()
+    hapd_global = hostapd.HostapdGlobal()
+    hapd_global.flush()
+    hapd_global.remove(apdev[0]['ifname'])
+
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'domain': "example.com" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
+    interworking_connect(dev[0], bssid, "TTLS")
+
+    # clear BSS table to avoid issues in following test cases
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    hapd.disable()
+    dev[0].flush_scan_cache()
+    dev[0].flush_scan_cache()
+
 def test_ap_hs20_proxyarp(dev, apdev):
     """Hotspot 2.0 and ProxyARP"""
-    res = None
     try:
-        res = _test_ap_hs20_proxyarp(dev, apdev)
+        _test_ap_hs20_proxyarp(dev, apdev)
     finally:
         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
                         stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delbr', 'ap-br0'],
                         stderr=open('/dev/null', 'w'))
 
-    return res
-
 def _test_ap_hs20_proxyarp_dgaf(dev, apdev, disabled):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
@@ -2437,8 +2631,7 @@
         hapd.enable()
     except:
         # For now, do not report failures due to missing kernel support
-        logger.info("Could not start hostapd - assume proxyarp not supported in kernel version")
-        return "skip"
+        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
     if ev is None:
         raise Exception("AP startup timed out")
@@ -2512,30 +2705,24 @@
 
 def test_ap_hs20_proxyarp_disable_dgaf(dev, apdev):
     """Hotspot 2.0 and ProxyARP with DGAF disabled"""
-    res = None
     try:
-        res = _test_ap_hs20_proxyarp_dgaf(dev, apdev, True)
+        _test_ap_hs20_proxyarp_dgaf(dev, apdev, True)
     finally:
         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
                         stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delbr', 'ap-br0'],
                         stderr=open('/dev/null', 'w'))
 
-    return res
-
 def test_ap_hs20_proxyarp_enable_dgaf(dev, apdev):
     """Hotspot 2.0 and ProxyARP with DGAF enabled"""
-    res = None
     try:
-        res = _test_ap_hs20_proxyarp_dgaf(dev, apdev, False)
+        _test_ap_hs20_proxyarp_dgaf(dev, apdev, False)
     finally:
         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
                         stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delbr', 'ap-br0'],
                         stderr=open('/dev/null', 'w'))
 
-    return res
-
 def ip_checksum(buf):
     sum = 0
     if len(buf) & 0x01:
@@ -2771,10 +2958,59 @@
     cmd.stdout.close()
     return [ line for line in res.splitlines() if "PERMANENT" in line and ifname in line ]
 
-def _test_proxyarp_open(dev, apdev, params):
-    cap_br = os.path.join(params['logdir'], "proxyarp_open.ap-br0.pcap")
-    cap_dev0 = os.path.join(params['logdir'], "proxyarp_open.%s.pcap" % dev[0].ifname)
-    cap_dev1 = os.path.join(params['logdir'], "proxyarp_open.%s.pcap" % dev[1].ifname)
+def get_bridge_macs(ifname):
+    cmd = subprocess.Popen(['brctl', 'showmacs', ifname],
+                           stdout=subprocess.PIPE)
+    res = cmd.stdout.read()
+    cmd.stdout.close()
+    return res
+
+def tshark_get_arp(cap, filter):
+    res = run_tshark(cap, filter,
+                     [ "eth.dst", "eth.src",
+                       "arp.src.hw_mac", "arp.src.proto_ipv4",
+                       "arp.dst.hw_mac", "arp.dst.proto_ipv4" ],
+                     wait=False)
+    frames = []
+    for l in res.splitlines():
+        frames.append(l.split('\t'))
+    return frames
+
+def tshark_get_ns(cap):
+    res = run_tshark(cap, "icmpv6.type == 135",
+                     [ "eth.dst", "eth.src",
+                       "ipv6.src", "ipv6.dst",
+                       "icmpv6.nd.ns.target_address",
+                       "icmpv6.opt.linkaddr" ],
+                     wait=False)
+    frames = []
+    for l in res.splitlines():
+        frames.append(l.split('\t'))
+    return frames
+
+def tshark_get_na(cap):
+    res = run_tshark(cap, "icmpv6.type == 136",
+                     [ "eth.dst", "eth.src",
+                       "ipv6.src", "ipv6.dst",
+                       "icmpv6.nd.na.target_address",
+                       "icmpv6.opt.linkaddr" ],
+                     wait=False)
+    frames = []
+    for l in res.splitlines():
+        frames.append(l.split('\t'))
+    return frames
+
+def _test_proxyarp_open(dev, apdev, params, ebtables=False):
+    prefix = "proxyarp_open"
+    if ebtables:
+        prefix += "_ebtables"
+    cap_br = os.path.join(params['logdir'], prefix + ".ap-br0.pcap")
+    cap_dev0 = os.path.join(params['logdir'],
+                            prefix + ".%s.pcap" % dev[0].ifname)
+    cap_dev1 = os.path.join(params['logdir'],
+                            prefix + ".%s.pcap" % dev[1].ifname)
+    cap_dev2 = os.path.join(params['logdir'],
+                            prefix + ".%s.pcap" % dev[2].ifname)
 
     bssid = apdev[0]['bssid']
     params = { 'ssid': 'open' }
@@ -2787,39 +3023,45 @@
         hapd.enable()
     except:
         # For now, do not report failures due to missing kernel support
-        logger.info("Could not start hostapd - assume proxyarp not supported in kernel version")
-        return "skip"
+        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
     if ev is None:
         raise Exception("AP startup timed out")
     if "AP-ENABLED" not in ev:
         raise Exception("AP startup failed")
 
+    params2 = { 'ssid': 'another' }
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params2, no_enable=True)
+    hapd2.set('bridge', 'ap-br0')
+    hapd2.enable()
+
     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
 
-    for chain in [ 'FORWARD', 'OUTPUT' ]:
-        subprocess.call(['ebtables', '-A', chain, '-p', 'ARP',
-                         '-d', 'Broadcast', '-o', apdev[0]['ifname'],
-                         '-j', 'DROP'])
-        subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
-                         '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
-                         '--ip6-icmp-type', 'neighbor-solicitation',
-                         '-o', apdev[0]['ifname'], '-j', 'DROP'])
-        subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
-                         '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
-                         '--ip6-icmp-type', 'neighbor-advertisement',
-                         '-o', apdev[0]['ifname'], '-j', 'DROP'])
-        subprocess.call(['ebtables', '-A', chain,
-                         '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
-                         '--ip6-icmp-type', 'router-solicitation',
-                         '-o', apdev[0]['ifname'], '-j', 'DROP'])
-        # Multicast Listener Report Message
-        subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
-                         '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
-                         '--ip6-icmp-type', '143',
-                         '-o', apdev[0]['ifname'], '-j', 'DROP'])
+    if ebtables:
+        for chain in [ 'FORWARD', 'OUTPUT' ]:
+            subprocess.call(['ebtables', '-A', chain, '-p', 'ARP',
+                             '-d', 'Broadcast', '-o', apdev[0]['ifname'],
+                             '-j', 'DROP'])
+            subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
+                             '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
+                             '--ip6-icmp-type', 'neighbor-solicitation',
+                             '-o', apdev[0]['ifname'], '-j', 'DROP'])
+            subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
+                             '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
+                             '--ip6-icmp-type', 'neighbor-advertisement',
+                             '-o', apdev[0]['ifname'], '-j', 'DROP'])
+            subprocess.call(['ebtables', '-A', chain,
+                             '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
+                             '--ip6-icmp-type', 'router-solicitation',
+                             '-o', apdev[0]['ifname'], '-j', 'DROP'])
+            # Multicast Listener Report Message
+            subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
+                             '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
+                             '--ip6-icmp-type', '143',
+                             '-o', apdev[0]['ifname'], '-j', 'DROP'])
 
+    time.sleep(0.5)
     cmd = {}
     cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'ap-br0',
                                '-w', cap_br, '-s', '2000'],
@@ -2830,13 +3072,29 @@
     cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', dev[1].ifname,
                                '-w', cap_dev1, '-s', '2000'],
                               stderr=open('/dev/null', 'w'))
+    cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', dev[2].ifname,
+                               '-w', cap_dev2, '-s', '2000'],
+                              stderr=open('/dev/null', 'w'))
 
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
+    dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
     time.sleep(0.1)
 
+    brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
+    res = brcmd.stdout.read()
+    brcmd.stdout.close()
+    logger.info("Bridge setup: " + res)
+
+    brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
+                             stdout=subprocess.PIPE)
+    res = brcmd.stdout.read()
+    brcmd.stdout.close()
+    logger.info("Bridge showstp: " + res)
+
     addr0 = dev[0].p2p_interface_addr()
     addr1 = dev[1].p2p_interface_addr()
+    addr2 = dev[2].p2p_interface_addr()
 
     src_ll_opt0 = "\x01\x01" + binascii.unhexlify(addr0.replace(':',''))
     src_ll_opt1 = "\x01\x01" + binascii.unhexlify(addr1.replace(':',''))
@@ -2930,6 +3188,9 @@
     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
         raise Exception("DATA_TEST_FRAME failed")
 
+    macs = get_bridge_macs("ap-br0")
+    logger.info("After connect (showmacs): " + str(macs))
+
     matches = get_permanent_neighbors("ap-br0")
     logger.info("After connect: " + str(matches))
     if len(matches) != 4:
@@ -2952,6 +3213,9 @@
         send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.101",
                  target_ip=target)
 
+    for target in targets:
+        send_arp(dev[2], sender_ip="192.168.1.103", target_ip=target)
+
     # ARP Probe from wireless STA
     send_arp(dev[1], target_ip="192.168.1.127")
     # ARP Announcement from wireless STA
@@ -2959,6 +3223,9 @@
     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127",
              opcode=2)
 
+    macs = get_bridge_macs("ap-br0")
+    logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
+
     matches = get_permanent_neighbors("ap-br0")
     logger.info("After ARP Probe + Announcement: " + str(matches))
 
@@ -2968,14 +3235,22 @@
     # ARP Request for the newly introduced IP address from bridge
     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
              target_ip="192.168.1.127")
+    send_arp(dev[2], sender_ip="192.168.1.103", target_ip="192.168.1.127")
 
     # ARP Probe from bridge
     send_arp(hapd, hapd_bssid=bssid, target_ip="192.168.1.130")
+    send_arp(dev[2], target_ip="192.168.1.131")
     # ARP Announcement from bridge (not to be learned by AP for proxyarp)
     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
              target_ip="192.168.1.130")
     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
              target_ip="192.168.1.130", opcode=2)
+    send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131")
+    send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131",
+             opcode=2)
+
+    macs = get_bridge_macs("ap-br0")
+    logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
 
     matches = get_permanent_neighbors("ap-br0")
     logger.info("After ARP Probe + Announcement: " + str(matches))
@@ -2986,9 +3261,16 @@
     send_arp(hapd, hapd_bssid=bssid, dst_ll=addr0, sender_ip="192.168.1.130",
              target_ip="192.168.1.123", opcode=2)
 
+    # ARP Request for the newly introduced IP address from wireless STA
+    send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.131")
+    # ARP Response from bridge (AP does not proxy for non-wireless devices)
+    send_arp(dev[2], dst_ll=addr0, sender_ip="192.168.1.131",
+             target_ip="192.168.1.123", opcode=2)
+
     # ARP Request for the newly introduced IP address from bridge
     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
              target_ip="192.168.1.130")
+    send_arp(dev[2], sender_ip="192.168.1.104", target_ip="192.168.1.131")
 
     # ARP Probe from wireless STA (duplicate address; learned through DHCP)
     send_arp(dev[1], target_ip="192.168.1.123")
@@ -3013,42 +3295,178 @@
     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:dddd::2",
             ip_src="aaaa:bbbb:ffff::2")
     time.sleep(0.1)
+    send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:ff00::2")
+    time.sleep(0.1)
+    send_ns(dev[2], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:ff00::2")
+    time.sleep(0.1)
+    send_ns(dev[2], target="aaaa:bbbb:eeee::2", ip_src="aaaa:bbbb:ff00::2")
+    time.sleep(0.1)
 
     # Try to probe for an already assigned address
     send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="::")
     time.sleep(0.1)
     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc::2", ip_src="::")
     time.sleep(0.1)
+    send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="::")
+    time.sleep(0.1)
 
     # Unsolicited NA
     send_na(dev[1], target="aaaa:bbbb:cccc:aeae::3",
             ip_src="aaaa:bbbb:cccc:aeae::3", ip_dst="ff02::1")
     send_na(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc:aeae::4",
             ip_src="aaaa:bbbb:cccc:aeae::4", ip_dst="ff02::1")
+    send_na(dev[2], target="aaaa:bbbb:cccc:aeae::5",
+            ip_src="aaaa:bbbb:cccc:aeae::5", ip_dst="ff02::1")
 
-    hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
+    try:
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
+    except Exception, e:
+        logger.info("test_connectibity_iface failed: " + str(e))
+        raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
     hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
     dev[0].request("DISCONNECT")
     dev[1].request("DISCONNECT")
     time.sleep(0.5)
-    for i in range(3):
+    for i in range(len(cmd)):
         cmd[i].terminate()
+    macs = get_bridge_macs("ap-br0")
+    logger.info("After disconnect (showmacs): " + str(macs))
     matches = get_permanent_neighbors("ap-br0")
     logger.info("After disconnect: " + str(matches))
     if len(matches) > 0:
         raise Exception("Unexpected neighbor entries after disconnect")
-    cmd = subprocess.Popen(['ebtables', '-L', '--Lc'], stdout=subprocess.PIPE)
-    res = cmd.stdout.read()
-    cmd.stdout.close()
-    logger.info("ebtables results:\n" + res)
+    if ebtables:
+        cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
+                               stdout=subprocess.PIPE)
+        res = cmd.stdout.read()
+        cmd.stdout.close()
+        logger.info("ebtables results:\n" + res)
+
+    # Verify that expected ARP messages were seen and no unexpected
+    # ARP messages were seen.
+
+    arp_req = tshark_get_arp(cap_dev0, "arp.opcode == 1")
+    arp_reply = tshark_get_arp(cap_dev0, "arp.opcode == 2")
+    logger.info("dev0 seen ARP requests:\n" + str(arp_req))
+    logger.info("dev0 seen ARP replies:\n" + str(arp_reply))
+
+    if [ 'ff:ff:ff:ff:ff:ff', addr1,
+         addr1, '192.168.1.100',
+         '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
+        raise Exception("dev0 saw ARP request from dev1")
+    if [ 'ff:ff:ff:ff:ff:ff', addr2,
+         addr2, '192.168.1.103',
+         '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
+        raise Exception("dev0 saw ARP request from dev2")
+    # TODO: Uncomment once fixed in kernel
+    #if [ 'ff:ff:ff:ff:ff:ff', bssid,
+    #     bssid, '192.168.1.101',
+    #     '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
+    #    raise Exception("dev0 saw ARP request from br")
+
+    if ebtables:
+        for req in arp_req:
+            if req[1] != addr0:
+                raise Exception("Unexpected foreign ARP request on dev0")
+
+    arp_req = tshark_get_arp(cap_dev1, "arp.opcode == 1")
+    arp_reply = tshark_get_arp(cap_dev1, "arp.opcode == 2")
+    logger.info("dev1 seen ARP requests:\n" + str(arp_req))
+    logger.info("dev1 seen ARP replies:\n" + str(arp_reply))
+
+    if [ 'ff:ff:ff:ff:ff:ff', addr2,
+         addr2, '192.168.1.103',
+         '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
+        raise Exception("dev1 saw ARP request from dev2")
+    if [addr1, addr0, addr0, '192.168.1.123', addr1, '192.168.1.100'] not in arp_reply:
+        raise Exception("dev1 did not get ARP response for 192.168.1.123")
+
+    if ebtables:
+        for req in arp_req:
+            if req[1] != addr1:
+                raise Exception("Unexpected foreign ARP request on dev1")
+
+    arp_req = tshark_get_arp(cap_dev2, "arp.opcode == 1")
+    arp_reply = tshark_get_arp(cap_dev2, "arp.opcode == 2")
+    logger.info("dev2 seen ARP requests:\n" + str(arp_req))
+    logger.info("dev2 seen ARP replies:\n" + str(arp_reply))
+
+    if [ addr2, addr0,
+         addr0, '192.168.1.123',
+         addr2, '192.168.1.103' ] not in arp_reply:
+        raise Exception("dev2 did not get ARP response for 192.168.1.123")
+
+    arp_req = tshark_get_arp(cap_br, "arp.opcode == 1")
+    arp_reply = tshark_get_arp(cap_br, "arp.opcode == 2")
+    logger.info("br seen ARP requests:\n" + str(arp_req))
+    logger.info("br seen ARP replies:\n" + str(arp_reply))
+
+    # TODO: Uncomment once fixed in kernel
+    #if [ bssid, addr0,
+    #     addr0, '192.168.1.123',
+    #     bssid, '192.168.1.101' ] not in arp_reply:
+    #    raise Exception("br did not get ARP response for 192.168.1.123")
+
+    ns = tshark_get_ns(cap_dev0)
+    logger.info("dev0 seen NS: " + str(ns))
+    na = tshark_get_na(cap_dev0)
+    logger.info("dev0 seen NA: " + str(na))
+
+    if [ addr0, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:cccc::2',
+         'aaaa:bbbb:dddd::2', addr1 ] not in na:
+        raise Exception("dev0 did not get NA for aaaa:bbbb:dddd::2")
+
+    if ebtables:
+        for req in ns:
+            if req[1] != addr0:
+                raise Exception("Unexpected foreign NS on dev0: " + str(req))
+
+    ns = tshark_get_ns(cap_dev1)
+    logger.info("dev1 seen NS: " + str(ns))
+    na = tshark_get_na(cap_dev1)
+    logger.info("dev1 seen NA: " + str(na))
+
+    if [ addr1, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:dddd::2',
+         'aaaa:bbbb:cccc::2', addr0 ] not in na:
+        raise Exception("dev1 did not get NA for aaaa:bbbb:cccc::2")
+
+    if ebtables:
+        for req in ns:
+            if req[1] != addr1:
+                raise Exception("Unexpected foreign NS on dev1: " + str(req))
+
+    ns = tshark_get_ns(cap_dev2)
+    logger.info("dev2 seen NS: " + str(ns))
+    na = tshark_get_na(cap_dev2)
+    logger.info("dev2 seen NA: " + str(na))
+
+    # FIX: enable once kernel implementation for proxyarp IPv6 is fixed
+    #if [ addr2, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:ff00::2',
+    #     'aaaa:bbbb:cccc::2', addr0 ] not in na:
+    #    raise Exception("dev2 did not get NA for aaaa:bbbb:cccc::2")
+    #if [ addr2, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:ff00::2',
+    #     'aaaa:bbbb:dddd::2', addr1 ] not in na:
+    #    raise Exception("dev2 did not get NA for aaaa:bbbb:dddd::2")
+    #if [ addr2, addr1, 'aaaa:bbbb:eeee::2', 'aaaa:bbbb:ff00::2',
+    #     'aaaa:bbbb:eeee::2', addr1 ] not in na:
+    #    raise Exception("dev2 did not get NA for aaaa:bbbb:eeee::2")
 
 def test_proxyarp_open(dev, apdev, params):
     """ProxyARP with open network"""
-    res = None
     try:
-        res = _test_proxyarp_open(dev, apdev, params)
+        _test_proxyarp_open(dev, apdev, params)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'ap-br0'],
+                        stderr=open('/dev/null', 'w'))
+
+def test_proxyarp_open_ebtables(dev, apdev, params):
+    """ProxyARP with open network"""
+    try:
+        _test_proxyarp_open(dev, apdev, params, ebtables=True)
     finally:
         try:
             subprocess.call(['ebtables', '-F', 'FORWARD'])
@@ -3059,5 +3477,3 @@
                         stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delbr', 'ap-br0'],
                         stderr=open('/dev/null', 'w'))
-
-    return res
diff --git a/tests/hwsim/test_ap_ht.py b/tests/hwsim/test_ap_ht.py
index 539413a..11e06e1 100644
--- a/tests/hwsim/test_ap_ht.py
+++ b/tests/hwsim/test_ap_ht.py
@@ -11,14 +11,15 @@
 import subprocess
 
 import hostapd
+from utils import HwsimSkip, alloc_fail
 import hwsim_utils
 from test_ap_csa import csa_supported
 
 def clear_scan_cache(ifname):
-    subprocess.call(['sudo', 'ifconfig', ifname, 'up'])
-    subprocess.call(['sudo', 'iw', ifname, 'scan', 'freq', '2412', 'flush'])
+    subprocess.call(['ifconfig', ifname, 'up'])
+    subprocess.call(['iw', ifname, 'scan', 'freq', '2412', 'flush'])
     time.sleep(0.1)
-    subprocess.call(['sudo', 'ifconfig', ifname, 'down'])
+    subprocess.call(['ifconfig', ifname, 'down'])
 
 def test_ap_ht40_scan(dev, apdev):
     """HT40 co-ex scan"""
@@ -225,7 +226,7 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_5ghz_switch(dev, apdev):
@@ -279,7 +280,7 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
 
 def test_ap_ht40_5ghz_switch2(dev, apdev):
     """HT40 co-ex scan on 5 GHz switching pri/sec channel (2)"""
@@ -341,7 +342,7 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_obss_scan(dev, apdev):
@@ -432,6 +433,69 @@
     if not received:
         raise Exception("20/40 BSS Coexistence report not seen")
 
+def test_obss_coex_report_handling(dev, apdev):
+    """Overlapping BSS scan report handling with obss_interval=0"""
+    clear_scan_cache(apdev[0]['ifname'])
+    params = { "ssid": "obss-scan",
+               "channel": "6",
+               "ht_capab": "[HT40-]" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
+
+    sec = hapd.get_status_field("secondary_channel")
+    if sec != "-1":
+        raise Exception("AP is not using 40 MHz channel")
+
+    # 20/40 MHz co-ex report tests: number of invalid reports and a valid report
+    # that forces 20 MHz channel.
+    tests = [ '0400', '040048', '04004801', '0400480000', '0400490100',
+              '040048ff0000', '04004801ff49ff00', '04004801004900',
+              '0400480100490101', '0400480100490201ff',
+              '040048010449020005' ]
+    for msg in tests:
+        req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
+        if "OK" not in dev[0].request(req):
+            raise Exception("Could not send management frame")
+    time.sleep(0.5)
+    sec = hapd.get_status_field("secondary_channel")
+    if sec != "0":
+        raise Exception("AP did not move to 20 MHz channel")
+
+def test_obss_coex_report_handling1(dev, apdev):
+    """Overlapping BSS scan report handling with obss_interval=1"""
+    clear_scan_cache(apdev[0]['ifname'])
+    params = { "ssid": "obss-scan",
+               "channel": "6",
+               "ht_capab": "[HT40+]",
+               "obss_interval": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
+
+    sec = hapd.get_status_field("secondary_channel")
+    if sec != "1":
+        raise Exception("AP is not using 40 MHz channel")
+
+    # 20/40 MHz co-ex report forcing 20 MHz channel
+    msg = '040048010449020005'
+    req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
+    if "OK" not in dev[0].request(req):
+        raise Exception("Could not send management frame")
+    time.sleep(0.5)
+    sec = hapd.get_status_field("secondary_channel")
+    if sec != "0":
+        raise Exception("AP did not move to 20 MHz channel")
+
+    # No 20/40 MHz co-ex reports forcing 20 MHz channel during next interval
+    for i in range(20):
+        sec = hapd.get_status_field("secondary_channel")
+        if sec == "1":
+            break
+        time.sleep(0.5)
+    if sec != "1":
+        raise Exception("AP did not return to 40 MHz channel")
+
 def test_olbc(dev, apdev):
     """OLBC detection"""
     params = { "ssid": "test-olbc",
@@ -467,6 +531,28 @@
     if not cleared:
         raise Exception("OLBC state did nto time out")
 
+def test_olbc_table_limit(dev, apdev):
+    """OLBC AP table size limit"""
+    ifname1 = apdev[0]['ifname']
+    ifname2 = apdev[0]['ifname'] + '-2'
+    ifname3 = apdev[0]['ifname'] + '-3'
+    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+
+    params = { "ssid": "test-olbc",
+               "channel": "1",
+               "ap_table_max_size": "2" }
+    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+
+    time.sleep(0.3)
+    with alloc_fail(hapd, 1, "ap_list_process_beacon"):
+        time.sleep(0.3)
+    hapd.set("ap_table_max_size", "1")
+    time.sleep(0.3)
+    hapd.set("ap_table_max_size", "0")
+    time.sleep(0.3)
+
 def test_olbc_5ghz(dev, apdev):
     """OLBC detection on 5 GHz"""
     try:
@@ -489,16 +575,22 @@
                    "ieee80211n": "0",
                    "wmm_enabled": "0" }
         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
-        time.sleep(0.5)
-        status = hapd.get_status()
-        if status['olbc_ht'] != '1':
+        found = False
+        for i in range(20):
+            time.sleep(0.1)
+            status = hapd.get_status()
+            logger.debug('olbc_ht: ' + status['olbc_ht'])
+            if status['olbc_ht'] == '1':
+                found = True
+                break
+        if not found:
             raise Exception("Missing OLBC information")
     finally:
         if hapd:
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
 
 def test_ap_require_ht(dev, apdev):
     """Require HT"""
@@ -630,8 +722,7 @@
 
 def test_ap_ht40_csa(dev, apdev):
     """HT with 40 MHz channel width and CSA"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     try:
         hapd = None
         params = { "ssid": "ht",
@@ -670,13 +761,12 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_csa2(dev, apdev):
     """HT with 40 MHz channel width and CSA"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     try:
         hapd = None
         params = { "ssid": "ht",
@@ -715,13 +805,12 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_csa3(dev, apdev):
     """HT with 40 MHz channel width and CSA"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     try:
         hapd = None
         params = { "ssid": "ht",
@@ -760,7 +849,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_ht_smps(dev, apdev):
@@ -769,8 +858,7 @@
     try:
         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     except:
-        logger.info("Assume mac80211_hwsim was not recent enough to support SMPS")
-        return "skip"
+        raise HwsimSkip("Assume mac80211_hwsim was not recent enough to support SMPS")
     params = { "ssid": "ht2", "ht_capab": "[SMPS-DYNAMIC]" }
     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
 
@@ -778,3 +866,81 @@
     dev[1].connect("ht2", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
     hwsim_utils.test_connectivity(dev[1], hapd2)
+
+def test_prefer_ht20(dev, apdev):
+    """Preference on HT20 over no-HT"""
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "0" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "1" }
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    bssid2 = apdev[1]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].scan_for_bss(bssid2, freq=2412)
+    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
+    if dev[0].get_status_field('bssid') != bssid2:
+        raise Exception("Unexpected BSS selected")
+
+    est = dev[0].get_bss(bssid)['est_throughput']
+    if est != "54000":
+        raise Exception("Unexpected BSS0 est_throughput: " + est)
+
+    est = dev[0].get_bss(bssid2)['est_throughput']
+    if est != "65000":
+        raise Exception("Unexpected BSS1 est_throughput: " + est)
+
+def test_prefer_ht40(dev, apdev):
+    """Preference on HT40 over HT20"""
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "1",
+               "ht_capab": "[HT40+]" }
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    bssid2 = apdev[1]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].scan_for_bss(bssid2, freq=2412)
+    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
+    if dev[0].get_status_field('bssid') != bssid2:
+        raise Exception("Unexpected BSS selected")
+
+    est = dev[0].get_bss(bssid)['est_throughput']
+    if est != "65000":
+        raise Exception("Unexpected BSS0 est_throughput: " + est)
+
+    est = dev[0].get_bss(bssid2)['est_throughput']
+    if est != "135000":
+        raise Exception("Unexpected BSS1 est_throughput: " + est)
+
+def test_prefer_ht20_during_roam(dev, apdev):
+    """Preference on HT20 over no-HT in roaming consideration"""
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "0" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
+
+    params = { "ssid": "test",
+               "channel": "1",
+               "ieee80211n": "1" }
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    bssid2 = apdev[1]['bssid']
+    dev[0].scan_for_bss(bssid2, freq=2412)
+    dev[0].scan(freq=2412)
+    dev[0].wait_connected()
+    
+    if dev[0].get_status_field('bssid') != bssid2:
+        raise Exception("Unexpected BSS selected")
diff --git a/tests/hwsim/test_ap_mixed.py b/tests/hwsim/test_ap_mixed.py
index 0173f51..5f03e7f 100644
--- a/tests/hwsim/test_ap_mixed.py
+++ b/tests/hwsim/test_ap_mixed.py
@@ -12,6 +12,8 @@
 
 def test_ap_mixed_security(dev, apdev):
     """WPA/WPA2 with PSK, EAP, SAE, FT in a single BSS"""
+    dev[0].flush_scan_cache()
+    sae = "SAE" in dev[0].get_capability("auth_alg")
     ssid = "test-mixed"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_mixed_params(ssid=ssid, passphrase=passphrase)
@@ -28,12 +30,15 @@
                    identity="gpsk user",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
-    dev[2].connect(ssid, psk=passphrase, key_mgmt="SAE", scan_freq="2412")
+    if sae:
+        dev[2].connect(ssid, psk=passphrase, key_mgmt="SAE", scan_freq="2412")
 
+    logger.debug(dev[0].request("SCAN_RESULTS"))
     bss = dev[0].get_bss(apdev[0]['bssid'])
+    logger.debug(bss)
     if "[WPA-EAP+PSK-TKIP]" not in bss['flags']:
         raise Exception("Unexpected flags (WPA): " + bss['flags'])
-    if "[WPA2-EAP+PSK+SAE+FT/EAP+FT/PSK+FT/SAE+EAP-SHA256+PSK-SHA256-CCMP]" not in bss['flags']:
+    if sae and "[WPA2-EAP+PSK+SAE+FT/EAP+FT/PSK+FT/SAE+EAP-SHA256+PSK-SHA256-CCMP]" not in bss['flags']:
         raise Exception("Unexpected flags (WPA2): " + bss['flags'])
 
     if dev[0].get_status_field("key_mgmt") != "WPA-PSK":
@@ -42,14 +47,16 @@
         raise Exception("Unexpected pairwise(1)")
     if dev[1].get_status_field("key_mgmt") != "WPA2-EAP-SHA256":
         raise Exception("Unexpected key_mgmt(2)")
-    if dev[2].get_status_field("key_mgmt") != "SAE":
+    if sae and dev[2].get_status_field("key_mgmt") != "SAE":
         raise Exception("Unexpected key_mgmt(3)")
 
     hwsim_utils.test_connectivity(dev[0], dev[1])
-    hwsim_utils.test_connectivity(dev[1], dev[2])
-    hwsim_utils.test_connectivity(dev[0], dev[2])
+    if sae:
+        hwsim_utils.test_connectivity(dev[1], dev[2])
+        hwsim_utils.test_connectivity(dev[0], dev[2])
     for i in range(3):
-        hwsim_utils.test_connectivity(dev[i], hapd)
+        if i < 2 or sae:
+            hwsim_utils.test_connectivity(dev[i], hapd)
         dev[i].request("DISCONNECT")
 
     dev[0].connect(ssid, key_mgmt="WPA-PSK WPA-PSK-SHA256", psk=passphrase,
@@ -58,8 +65,9 @@
                    identity="gpsk user",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
-    dev[2].connect(ssid, key_mgmt="WPA-PSK WPA-PSK-SHA256 SAE", psk=passphrase,
-                   scan_freq="2412")
+    if sae:
+        dev[2].connect(ssid, key_mgmt="WPA-PSK WPA-PSK-SHA256 SAE",
+                       psk=passphrase, scan_freq="2412")
 
     if dev[0].get_status_field("key_mgmt") != "WPA2-PSK-SHA256":
         raise Exception("Unexpected key_mgmt(1b)")
@@ -67,7 +75,7 @@
         raise Exception("Unexpected pairwise(1b)")
     if dev[1].get_status_field("key_mgmt") != "WPA/IEEE 802.1X/EAP":
         raise Exception("Unexpected key_mgmt(2b)")
-    if dev[2].get_status_field("key_mgmt") != "SAE":
+    if sae and dev[2].get_status_field("key_mgmt") != "SAE":
         raise Exception("Unexpected key_mgmt(3b)")
 
     for i in range(3):
@@ -77,11 +85,13 @@
     dev[1].connect(ssid, key_mgmt="FT-EAP", eap="GPSK", identity="gpsk user",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
-    dev[2].connect(ssid, psk=passphrase, key_mgmt="FT-SAE", scan_freq="2412")
+    if sae:
+        dev[2].connect(ssid, psk=passphrase, key_mgmt="FT-SAE",
+                       scan_freq="2412")
 
     if dev[0].get_status_field("key_mgmt") != "FT-PSK":
         raise Exception("Unexpected key_mgmt(1c)")
     if dev[1].get_status_field("key_mgmt") != "FT-EAP":
         raise Exception("Unexpected key_mgmt(2c)")
-    if dev[2].get_status_field("key_mgmt") != "FT-SAE":
+    if sae and dev[2].get_status_field("key_mgmt") != "FT-SAE":
         raise Exception("Unexpected key_mgmt(3c)")
diff --git a/tests/hwsim/test_ap_open.py b/tests/hwsim/test_ap_open.py
index 9f7c80a..7ed517b 100644
--- a/tests/hwsim/test_ap_open.py
+++ b/tests/hwsim/test_ap_open.py
@@ -9,9 +9,13 @@
 import struct
 import subprocess
 import time
+import os
 
 import hostapd
 import hwsim_utils
+from tshark import run_tshark
+from utils import alloc_fail
+from wpasupplicant import WpaSupplicant
 
 def test_ap_open(dev, apdev):
     """AP with open mode (no security) configuration"""
@@ -164,3 +168,264 @@
         hwsim_utils.test_connectivity(dev[0], hapd)
         hwsim_utils.test_connectivity(dev[0], hapd)
         time.sleep(0.15)
+
+def hapd_out_of_mem(hapd, apdev, count, func):
+    with alloc_fail(hapd, count, func):
+        started = False
+        try:
+            hostapd.add_ap(apdev['ifname'], { "ssid": "open" })
+            started = True
+        except:
+            pass
+        if started:
+            raise Exception("hostapd interface started even with memory allocation failure: " + arg)
+
+def test_ap_open_out_of_memory(dev, apdev):
+    """hostapd failing to setup interface due to allocation failure"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd_out_of_mem(hapd, apdev[1], 1, "hostapd_alloc_bss_data")
+
+    for i in range(1, 3):
+        hapd_out_of_mem(hapd, apdev[1], i, "hostapd_iface_alloc")
+
+    for i in range(1, 5):
+        hapd_out_of_mem(hapd, apdev[1], i, "hostapd_config_defaults;hostapd_config_alloc")
+
+    hapd_out_of_mem(hapd, apdev[1], 1, "hostapd_config_alloc")
+
+    hapd_out_of_mem(hapd, apdev[1], 1, "hostapd_driver_init")
+
+    for i in range(1, 4):
+        hapd_out_of_mem(hapd, apdev[1], i, "=wpa_driver_nl80211_drv_init")
+
+    # eloop_register_read_sock() call from i802_init()
+    hapd_out_of_mem(hapd, apdev[1], 1, "eloop_sock_table_add_sock;eloop_register_sock;?eloop_register_read_sock;=i802_init")
+
+    # verify that a new interface can still be added when memory allocation does
+    # not fail
+    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+
+def test_bssid_black_white_list(dev, apdev):
+    """BSSID black/white list"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_whitelist=apdev[1]['bssid'])
+    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_blacklist=apdev[1]['bssid'])
+    dev[2].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_whitelist="00:00:00:00:00:00/00:00:00:00:00:00",
+                   bssid_blacklist=apdev[1]['bssid'])
+    if dev[0].get_status_field('bssid') != apdev[1]['bssid']:
+        raise Exception("dev[0] connected to unexpected AP")
+    if dev[1].get_status_field('bssid') != apdev[0]['bssid']:
+        raise Exception("dev[1] connected to unexpected AP")
+    if dev[2].get_status_field('bssid') != apdev[0]['bssid']:
+        raise Exception("dev[2] connected to unexpected AP")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[1].request("REMOVE_NETWORK all")
+    dev[2].request("REMOVE_NETWORK all")
+
+    dev[2].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_whitelist="00:00:00:00:00:00", wait_connect=False)
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_whitelist="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
+    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bssid_blacklist="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
+    if dev[0].get_status_field('bssid') != apdev[1]['bssid']:
+        raise Exception("dev[0] connected to unexpected AP")
+    if dev[1].get_status_field('bssid') != apdev[0]['bssid']:
+        raise Exception("dev[1] connected to unexpected AP")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[1].request("REMOVE_NETWORK all")
+    ev = dev[2].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected dev[2] connectin")
+    dev[2].request("REMOVE_NETWORK all")
+
+def test_ap_open_wpas_in_bridge(dev, apdev):
+    """Open mode AP and wpas interface in a bridge"""
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    try:
+        _test_ap_open_wpas_in_bridge(dev, apdev)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
+        subprocess.call(['brctl', 'delif', br_ifname, ifname])
+        subprocess.call(['brctl', 'delbr', br_ifname])
+        subprocess.call(['iw', ifname, 'set', '4addr', 'off'])
+
+def _test_ap_open_wpas_in_bridge(dev, apdev):
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    # First, try a failure case of adding an interface
+    try:
+        wpas.interface_add(ifname, br_ifname=br_ifname)
+        raise Exception("Interface addition succeeded unexpectedly")
+    except Exception, e:
+        if "Failed to add" in str(e):
+            logger.info("Ignore expected interface_add failure due to missing bridge interface: " + str(e))
+        else:
+            raise
+
+    # Next, add the bridge interface and add the interface again
+    subprocess.call(['brctl', 'addbr', br_ifname])
+    subprocess.call(['brctl', 'setfd', br_ifname, '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
+    subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
+    subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
+    wpas.interface_add(ifname, br_ifname=br_ifname)
+
+    wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+
+def test_ap_open_start_disabled(dev, apdev):
+    """AP with open mode and beaconing disabled"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open",
+                                                "start_disabled": "1" })
+    bssid = apdev[0]['bssid']
+
+    dev[0].flush_scan_cache()
+    dev[0].scan(freq=2412, only_new=True)
+    if dev[0].get_bss(bssid) is not None:
+        raise Exception("AP was seen beaconing")
+    if "OK" not in hapd.request("RELOAD"):
+        raise Exception("RELOAD failed")
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+
+def test_ap_open_start_disabled2(dev, apdev):
+    """AP with open mode and beaconing disabled (2)"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open",
+                                                "start_disabled": "1" })
+    bssid = apdev[0]['bssid']
+
+    dev[0].flush_scan_cache()
+    dev[0].scan(freq=2412, only_new=True)
+    if dev[0].get_bss(bssid) is not None:
+        raise Exception("AP was seen beaconing")
+    if "OK" not in hapd.request("UPDATE_BEACON"):
+        raise Exception("UPDATE_BEACON failed")
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    if "OK" not in hapd.request("UPDATE_BEACON"):
+        raise Exception("UPDATE_BEACON failed")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    dev[0].request("RECONNECT")
+    dev[0].wait_connected()
+
+def test_ap_open_ifdown(dev, apdev):
+    """AP with open mode and external ifconfig down"""
+    params = { "ssid": "open",
+               "ap_max_inactivity": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
+    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
+    ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("Timeout on AP-STA-DISCONNECTED (1)")
+    ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on AP-STA-DISCONNECTED (2)")
+    ev = hapd.wait_event(["INTERFACE-DISABLED"], timeout=5)
+    if ev is None:
+        raise Exception("No INTERFACE-DISABLED event")
+    # The following wait tests beacon loss detection in mac80211 on dev0.
+    # dev1 is used to test stopping of AP side functionality on client polling.
+    dev[1].request("REMOVE_NETWORK all")
+    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
+    dev[0].wait_disconnected()
+    dev[1].wait_disconnected()
+    ev = hapd.wait_event(["INTERFACE-ENABLED"], timeout=10)
+    if ev is None:
+        raise Exception("No INTERFACE-ENABLED event")
+    dev[0].wait_connected()
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_open_disconnect_in_ps(dev, apdev, params):
+    """Disconnect with the client in PS to regression-test a kernel bug"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bg_scan_period="0")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
+
+    time.sleep(0.2)
+    hwsim_utils.set_powersave(dev[0], hwsim_utils.PS_MANUAL_POLL)
+    try:
+        # inject some traffic
+        sa = hapd.own_addr()
+        da = dev[0].own_addr()
+        hapd.request('DATA_TEST_CONFIG 1')
+        hapd.request('DATA_TEST_TX {} {} 0'.format(da, sa))
+        hapd.request('DATA_TEST_CONFIG 0')
+
+        # let the AP send couple of Beacon frames
+        time.sleep(0.3)
+
+        # disconnect - with traffic pending - shouldn't cause kernel warnings
+        dev[0].request("DISCONNECT")
+    finally:
+        hwsim_utils.set_powersave(dev[0], hwsim_utils.PS_DISABLED)
+
+    time.sleep(0.2)
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan_mgt.tim.partial_virtual_bitmap",
+                     ["wlan_mgt.tim.partial_virtual_bitmap"])
+    if out is not None:
+        state = 0
+        for l in out.splitlines():
+            pvb = int(l, 16)
+            if pvb > 0 and state == 0:
+                state = 1
+            elif pvb == 0 and state == 1:
+                state = 2
+        if state != 2:
+            raise Exception("Didn't observe TIM bit getting set and unset (state=%d)" % state)
+
+def test_ap_open_select_network(dev, apdev):
+    """Open mode connection and SELECT_NETWORK to change network"""
+    hapd1 = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    bssid1 = apdev[0]['bssid']
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open2" })
+    bssid2 = apdev[1]['bssid']
+
+    id1 = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                         only_add_network=True)
+    id2 = dev[0].connect("open2", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd2)
+
+    dev[0].select_network(id1)
+    dev[0].wait_connected()
+    res = dev[0].request("BLACKLIST")
+    if bssid1 in res or bssid2 in res:
+        raise Exception("Unexpected blacklist entry")
+    hwsim_utils.test_connectivity(dev[0], hapd1)
+
+    dev[0].select_network(id2)
+    dev[0].wait_connected()
+    hwsim_utils.test_connectivity(dev[0], hapd2)
+    res = dev[0].request("BLACKLIST")
+    if bssid1 in res or bssid2 in res:
+        raise Exception("Unexpected blacklist entry(2)")
+
+def test_ap_open_disable_enable(dev, apdev):
+    """AP with open mode getting disabled and re-enabled"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bg_scan_period="0")
+
+    for i in range(2):
+        hapd.request("DISABLE")
+        dev[0].wait_disconnected()
+        hapd.request("ENABLE")
+        dev[0].wait_connected()
+        hwsim_utils.test_connectivity(dev[0], hapd)
diff --git a/tests/hwsim/test_ap_params.py b/tests/hwsim/test_ap_params.py
index 5558ccf..e91bfac 100644
--- a/tests/hwsim/test_ap_params.py
+++ b/tests/hwsim/test_ap_params.py
@@ -74,7 +74,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acl_accept(dev, apdev):
@@ -123,17 +123,17 @@
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
 
     try:
-        subprocess.call(['sudo', 'brctl', 'addbr', 'wds-br0'])
-        subprocess.call(['sudo', 'brctl', 'setfd', 'wds-br0', '0'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'wds-br0', 'up'])
-        subprocess.call(['sudo', 'iw', dev[0].ifname, 'set', '4addr', 'on'])
+        subprocess.call(['brctl', 'addbr', 'wds-br0'])
+        subprocess.call(['brctl', 'setfd', 'wds-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'wds-br0', 'up'])
+        subprocess.call(['iw', dev[0].ifname, 'set', '4addr', 'on'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
         hwsim_utils.test_connectivity_iface(dev[0], hapd, "wds-br0",
                                             max_tries=15)
     finally:
-        subprocess.call(['sudo', 'iw', dev[0].ifname, 'set', '4addr', 'off'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'wds-br0', 'down'])
-        subprocess.call(['sudo', 'brctl', 'delbr', 'wds-br0'])
+        subprocess.call(['iw', dev[0].ifname, 'set', '4addr', 'off'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'wds-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'wds-br0'])
 
 def test_ap_inactivity_poll(dev, apdev):
     """AP using inactivity poll"""
@@ -209,7 +209,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_max_listen_interval(dev, apdev):
diff --git a/tests/hwsim/test_ap_pmf.py b/tests/hwsim/test_ap_pmf.py
index b7c7419..ffb7b7b 100644
--- a/tests/hwsim/test_ap_pmf.py
+++ b/tests/hwsim/test_ap_pmf.py
@@ -168,7 +168,7 @@
 def test_ap_pmf_sta_sa_query(dev, apdev):
     """WPA2-PSK AP with station using SA Query"""
     ssid = "assoc-comeback"
-    addr = dev[0].p2p_dev_addr()
+    addr = dev[0].own_addr()
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
@@ -186,7 +186,7 @@
     wpas.set_network(id, "group", "CCMP")
     wpas.set_network(id, "frequency", "2412")
     wpas.connect_network(id)
-    bssid = wpas.p2p_dev_addr()
+    bssid = wpas.own_addr()
 
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
@@ -207,10 +207,46 @@
     if wt.get_sta_counter("valid_saqueryresp_rx", bssid, addr) < 1:
         raise Exception("AP did not reply to SA Query")
 
+def test_ap_pmf_sta_sa_query_no_response(dev, apdev):
+    """WPA2-PSK AP with station using SA Query and getting no response"""
+    ssid = "assoc-comeback"
+    addr = dev[0].p2p_dev_addr()
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5", drv_params="use_monitor=1")
+    id = wpas.add_network()
+    wpas.set_network(id, "mode", "2")
+    wpas.set_network_quoted(id, "ssid", ssid)
+    wpas.set_network(id, "proto", "WPA2")
+    wpas.set_network(id, "key_mgmt", "WPA-PSK-SHA256")
+    wpas.set_network(id, "ieee80211w", "2")
+    wpas.set_network_quoted(id, "psk", "12345678")
+    wpas.set_network(id, "pairwise", "CCMP")
+    wpas.set_network(id, "group", "CCMP")
+    wpas.set_network(id, "frequency", "2412")
+    wpas.connect_network(id)
+    bssid = wpas.own_addr()
+
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                   scan_freq="2412")
+    wpas.request("DEAUTHENTICATE " + addr + " test=0")
+    wpas.request("DISASSOCIATE " + addr + " test=0")
+    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
+    if ev is not None:
+        raise Exception("Unexpected disconnection")
+
+    wpas.request("SET ext_mgmt_frame_handling 1")
+    wpas.request("DEAUTHENTICATE " + addr + " reason=6 test=0")
+    wpas.request("DISASSOCIATE " + addr + " reason=7 test=0")
+    dev[0].wait_disconnected()
+    wpas.request("SET ext_mgmt_frame_handling 0")
+    dev[0].wait_connected()
+
 def test_ap_pmf_sta_unprot_deauth_burst(dev, apdev):
     """WPA2-PSK AP with station receiving burst of unprotected Deauthentication frames"""
     ssid = "deauth-attack"
-    addr = dev[0].p2p_dev_addr()
+    addr = dev[0].own_addr()
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
@@ -293,3 +329,59 @@
     if "[WPA2-PSK-CCMP]" not in dev[0].request("SCAN_RESULTS"):
         raise Exception("Scan results missing RSN element info")
     hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_pmf_toggle(dev, apdev):
+    """WPA2-PSK AP with PMF optional and changing PMF on reassociation"""
+    try:
+        _test_ap_pmf_toggle(dev, apdev)
+    finally:
+        dev[0].request("SET reassoc_same_bss_optim 0")
+
+def _test_ap_pmf_toggle(dev, apdev):
+    ssid = "test-pmf-optional"
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK";
+    params["ieee80211w"] = "1";
+    params["assoc_sa_query_max_timeout"] = "1"
+    params["assoc_sa_query_retry_timeout"] = "1"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+    addr = dev[0].own_addr()
+    dev[0].request("SET reassoc_same_bss_optim 1")
+    id = dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                        key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                        scan_freq="2412")
+    wt.require_ap_pmf_optional(bssid)
+    wt.require_sta_pmf(bssid, addr)
+    sta = hapd.get_sta(addr)
+    if '[MFP]' not in sta['flags']:
+        raise Exception("MFP flag not present for STA")
+
+    dev[0].set_network(id, "ieee80211w", "0")
+    dev[0].request("REASSOCIATE")
+    dev[0].wait_connected()
+    wt.require_sta_no_pmf(bssid, addr)
+    sta = hapd.get_sta(addr)
+    if '[MFP]' in sta['flags']:
+        raise Exception("MFP flag unexpectedly present for STA")
+    cmd = subprocess.Popen(['iw', 'dev', apdev[0]['ifname'], 'station', 'get',
+                            addr], stdout=subprocess.PIPE)
+    (data,err) = cmd.communicate()
+    if "yes" in [l for l in data.splitlines() if "MFP" in l][0]:
+        raise Exception("Kernel STA entry had MFP enabled")
+
+    dev[0].set_network(id, "ieee80211w", "1")
+    dev[0].request("REASSOCIATE")
+    dev[0].wait_connected()
+    wt.require_sta_pmf(bssid, addr)
+    sta = hapd.get_sta(addr)
+    if '[MFP]' not in sta['flags']:
+        raise Exception("MFP flag not present for STA")
+    cmd = subprocess.Popen(['iw', 'dev', apdev[0]['ifname'], 'station', 'get',
+                            addr], stdout=subprocess.PIPE)
+    (data,err) = cmd.communicate()
+    if "yes" not in [l for l in data.splitlines() if "MFP" in l][0]:
+        raise Exception("Kernel STA entry did not have MFP enabled")
diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py
index b3a81b7..7213143 100644
--- a/tests/hwsim/test_ap_psk.py
+++ b/tests/hwsim/test_ap_psk.py
@@ -5,17 +5,21 @@
 # See README for more details.
 
 import binascii
+from Crypto.Cipher import AES
 import hashlib
 import hmac
 import logging
 logger = logging.getLogger()
 import os
+import re
 import struct
 import subprocess
 import time
 
 import hostapd
+from utils import HwsimSkip
 import hwsim_utils
+from wpasupplicant import WpaSupplicant
 
 def check_mib(dev, vals):
     mib = dev.get_mib()
@@ -64,6 +68,40 @@
         raise Exception("Timed out while waiting for failure report")
     dev[1].request("REMOVE_NETWORK all")
 
+def test_ap_wpa2_psk_mem(dev, apdev):
+    """WPA2-PSK AP with passphrase only in memory"""
+    try:
+        _test_ap_wpa2_psk_mem(dev, apdev)
+    finally:
+        dev[0].request("SCAN_INTERVAL 5")
+        dev[1].request("SCAN_INTERVAL 5")
+
+def _test_ap_wpa2_psk_mem(dev, apdev):
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+    params = hostapd.wpa2_params(ssid=ssid)
+    params['wpa_psk'] = psk
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].connect(ssid, mem_only_psk="1", scan_freq="2412", wait_connect=False)
+    dev[0].request("SCAN_INTERVAL 1")
+    ev = dev[0].wait_event(["CTRL-REQ-PSK_PASSPHRASE"], timeout=10)
+    if ev is None:
+        raise Exception("Request for PSK/passphrase timed out")
+    id = ev.split(':')[0].split('-')[-1]
+    dev[0].request("CTRL-RSP-PSK_PASSPHRASE-" + id + ':"' + passphrase + '"')
+    dev[0].wait_connected(timeout=10)
+
+    dev[1].connect(ssid, mem_only_psk="1", scan_freq="2412", wait_connect=False)
+    dev[1].request("SCAN_INTERVAL 1")
+    ev = dev[1].wait_event(["CTRL-REQ-PSK_PASSPHRASE"], timeout=10)
+    if ev is None:
+        raise Exception("Request for PSK/passphrase timed out(2)")
+    id = ev.split(':')[0].split('-')[-1]
+    dev[1].request("CTRL-RSP-PSK_PASSPHRASE-" + id + ':' + psk)
+    dev[1].wait_connected(timeout=10)
+
 def test_ap_wpa2_ptk_rekey(dev, apdev):
     """WPA2-PSK AP and PTK rekey enforced by station"""
     ssid = "test-wpa2-psk"
@@ -169,9 +207,9 @@
 
 def test_ap_wpa2_psk_file(dev, apdev):
     """WPA2-PSK AP with various PSK file error and success cases"""
-    addr0 = dev[0].p2p_dev_addr()
-    addr1 = dev[1].p2p_dev_addr()
-    addr2 = dev[2].p2p_dev_addr()
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    addr2 = dev[2].own_addr()
     ssid = "psk"
     pskfile = "/tmp/ap_wpa2_psk_file_errors.psk_file"
     try:
@@ -305,8 +343,8 @@
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
         params['bridge'] = 'ap-br0'
         hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['sudo', 'brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
                        bssid=apdev[0]['bssid'])
         dev[1].connect(ssid, psk=passphrase, scan_freq="2412",
@@ -329,8 +367,8 @@
         if addr0 in macs2 or addr1 in macs2:
             raise Exception("Bridge FDB entry was not removed")
     finally:
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['sudo', 'brctl', 'delbr', 'ap-br0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'ap-br0'])
 
 def test_ap_wpa2_already_in_bridge(dev, apdev):
     """hostapd behavior with interface already in bridge"""
@@ -588,7 +626,7 @@
     hapd = hostapd.add_ap(apdev['ifname'], params)
     hapd.request("SET ext_eapol_frame_io 1")
     dev.request("SET ext_eapol_frame_io 1")
-    dev.connect(ssid, psk="not used", scan_freq="2412", wait_connect=False)
+    dev.connect(ssid, raw_psk=psk, scan_freq="2412", wait_connect=False)
     addr = dev.p2p_interface_addr()
     if wpa2:
         rsne = binascii.unhexlify('30140100000fac040100000fac040100000fac020000')
@@ -818,3 +856,1061 @@
 
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
+
+def build_eapol_key_1_4(anonce, replay_counter=1, key_data='', key_len=16):
+    msg = {}
+    msg['version'] = 2
+    msg['type'] = 3
+    msg['length'] = 95 + len(key_data)
+
+    msg['descr_type'] = 2
+    msg['rsn_key_info'] = 0x8a
+    msg['rsn_key_len'] = key_len
+    msg['rsn_replay_counter'] = struct.pack('>Q', replay_counter)
+    msg['rsn_key_nonce'] = anonce
+    msg['rsn_key_iv'] = binascii.unhexlify('00000000000000000000000000000000')
+    msg['rsn_key_rsc'] = binascii.unhexlify('0000000000000000')
+    msg['rsn_key_id'] = binascii.unhexlify('0000000000000000')
+    msg['rsn_key_mic'] = binascii.unhexlify('00000000000000000000000000000000')
+    msg['rsn_key_data_len'] = len(key_data)
+    msg['rsn_key_data'] = key_data
+    return msg
+
+def build_eapol_key_3_4(anonce, kck, key_data, replay_counter=2,
+                        key_info=0x13ca, extra_len=0, descr_type=2, key_len=16):
+    msg = {}
+    msg['version'] = 2
+    msg['type'] = 3
+    msg['length'] = 95 + len(key_data) + extra_len
+
+    msg['descr_type'] = descr_type
+    msg['rsn_key_info'] = key_info
+    msg['rsn_key_len'] = key_len
+    msg['rsn_replay_counter'] = struct.pack('>Q', replay_counter)
+    msg['rsn_key_nonce'] = anonce
+    msg['rsn_key_iv'] = binascii.unhexlify('00000000000000000000000000000000')
+    msg['rsn_key_rsc'] = binascii.unhexlify('0000000000000000')
+    msg['rsn_key_id'] = binascii.unhexlify('0000000000000000')
+    msg['rsn_key_data_len'] = len(key_data)
+    msg['rsn_key_data'] = key_data
+    eapol_key_mic(kck, msg)
+    return msg
+
+def aes_wrap(kek, plain):
+    n = len(plain) / 8
+    a = 0xa6a6a6a6a6a6a6a6
+    enc = AES.new(kek).encrypt
+    r = [plain[i * 8:(i + 1) * 8] for i in range(0, n)]
+    for j in range(6):
+        for i in range(1, n + 1):
+            b = enc(struct.pack('>Q', a) + r[i - 1])
+            a = struct.unpack('>Q', b[:8])[0] ^ (n * j + i)
+            r[i - 1] =b[8:]
+    return struct.pack('>Q', a) + ''.join(r)
+
+def pad_key_data(plain):
+    pad_len = len(plain) % 8
+    if pad_len:
+        pad_len = 8 - pad_len
+        plain += '\xdd'
+        pad_len -= 1
+        plain += pad_len * '\0'
+    return plain
+
+def test_ap_wpa2_psk_supp_proto(dev, apdev):
+    """WPA2-PSK 4-way handshake protocol testing for supplicant"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Invalid AES wrap data length 0")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '', replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported AES-WRAP len 0"])
+    if ev is None:
+        raise Exception("Unsupported AES-WRAP len 0 not reported")
+
+    logger.debug("Invalid AES wrap data length 1")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '1', replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported AES-WRAP len 1"])
+    if ev is None:
+        raise Exception("Unsupported AES-WRAP len 1 not reported")
+
+    logger.debug("Invalid AES wrap data length 9")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '123456789', replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported AES-WRAP len 9"])
+    if ev is None:
+        raise Exception("Unsupported AES-WRAP len 9 not reported")
+
+    logger.debug("Invalid AES wrap data payload")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter)
+    # do not increment counter to test replay protection
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: AES unwrap failed"])
+    if ev is None:
+        raise Exception("AES unwrap failure not reported")
+
+    logger.debug("Replay Count not increasing")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: EAPOL-Key Replay Counter did not increase"])
+    if ev is None:
+        raise Exception("Replay Counter replay not reported")
+
+    logger.debug("Missing Ack bit in key info")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              key_info=0x134a)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: No Ack bit in key_info"])
+    if ev is None:
+        raise Exception("Missing Ack bit not reported")
+
+    logger.debug("Unexpected Request bit in key info")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              key_info=0x1bca)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: EAPOL-Key with Request bit"])
+    if ev is None:
+        raise Exception("Request bit not reported")
+
+    logger.debug("Unsupported key descriptor version 0")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13c8)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 0"])
+    if ev is None:
+        raise Exception("Unsupported EAPOL-Key descriptor version 0 not reported")
+
+    logger.debug("Key descriptor version 1 not allowed with CCMP")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13c9)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: CCMP is used, but EAPOL-Key descriptor version (1) is not 2"])
+    if ev is None:
+        raise Exception("Not allowed EAPOL-Key descriptor version not reported")
+
+    logger.debug("Invalid AES wrap payload with key descriptor version 2")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13ca)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: AES unwrap failed"])
+    if ev is None:
+        raise Exception("AES unwrap failure not reported")
+
+    logger.debug("Key descriptor version 3 workaround")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13cb)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: CCMP is used, but EAPOL-Key descriptor version (3) is not 2"])
+    if ev is None:
+        raise Exception("CCMP key descriptor mismatch not reported")
+    ev = dev[0].wait_event(["WPA: Interoperability workaround"])
+    if ev is None:
+        raise Exception("AES-128-CMAC workaround not reported")
+    ev = dev[0].wait_event(["WPA: Invalid EAPOL-Key MIC - dropping packet"])
+    if ev is None:
+        raise Exception("MIC failure with AES-128-CMAC workaround not reported")
+
+    logger.debug("Unsupported key descriptor version 4")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13cc)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 4"])
+    if ev is None:
+        raise Exception("Unsupported EAPOL-Key descriptor version 4 not reported")
+
+    logger.debug("Unsupported key descriptor version 7")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '0123456789abcdef',
+                              replay_counter=counter, key_info=0x13cf)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 7"])
+    if ev is None:
+        raise Exception("Unsupported EAPOL-Key descriptor version 7 not reported")
+
+    logger.debug("Too short EAPOL header length")
+    dev[0].dump_monitor()
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              extra_len=-1)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Invalid EAPOL-Key frame - key_data overflow (8 > 7)"])
+    if ev is None:
+        raise Exception("Key data overflow not reported")
+
+    logger.debug("Too long EAPOL header length")
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              extra_len=1)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+
+    logger.debug("Unsupported descriptor type 0")
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              descr_type=0)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+
+    logger.debug("WPA descriptor type 0")
+    msg = build_eapol_key_3_4(anonce, kck, '12345678', replay_counter=counter,
+                              descr_type=254)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+
+    logger.debug("Non-zero key index for pairwise key")
+    dev[0].dump_monitor()
+    wrapped = aes_wrap(kek, 16*'z')
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_info=0x13ea)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Ignored EAPOL-Key (Pairwise) with non-zero key index"])
+    if ev is None:
+        raise Exception("Non-zero key index not reported")
+
+    logger.debug("Invalid Key Data plaintext payload --> disconnect")
+    dev[0].dump_monitor()
+    wrapped = aes_wrap(kek, 16*'z')
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_no_ie(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: IE not included"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("No IEs in msg 3/4 --> disconnect")
+    dev[0].dump_monitor()
+    wrapped = aes_wrap(kek, 16*'\0')
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_ie_mismatch(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: IE mismatch"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Msg 3/4 with mismatching IE")
+    dev[0].dump_monitor()
+    wrapped = aes_wrap(kek, pad_key_data(binascii.unhexlify('30060100000fac04dd16000fac010100dc11188831bf4aa4a8678d2b41498618')))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_ok(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: success"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010100dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_connected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_no_gtk(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: no GTK"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("EAPOL-Key msg 3/4 without GTK KDE")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected connection completion reported")
+
+def test_ap_wpa2_psk_supp_proto_anonce_change(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: ANonce change"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    anonce2 = binascii.unhexlify('3333333333333333333333333333333333333333333333333333333333333333')
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010100dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce2, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: ANonce from message 1 of 4-Way Handshake differs from 3 of 4-Way Handshake"])
+    if ev is None:
+        raise Exception("ANonce change not reported")
+
+def test_ap_wpa2_psk_supp_proto_unexpected_group_msg(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: unexpected group message"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Group key 1/2 instead of msg 3/4")
+    dev[0].dump_monitor()
+    wrapped = aes_wrap(kek, binascii.unhexlify('dd16000fac010100dc11188831bf4aa4a8678d2b41498618'))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_info=0x13c2)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Group Key Handshake started prior to completion of 4-way handshake"])
+    if ev is None:
+        raise Exception("Unexpected group key message not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_msg_1_invalid_kde(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: invalid KDE in msg 1/4"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4 with invalid KDE
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter,
+                              key_data=binascii.unhexlify('5555'))
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_wrong_pairwise_key_len(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: wrong pairwise key length"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010100dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_len=15)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Invalid CCMP key length 15"])
+    if ev is None:
+        raise Exception("Invalid CCMP key length not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_wrong_group_key_len(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: wrong group key length"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd15000fac010100dc11188831bf4aa4a8678d2b414986')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported CCMP Group Cipher key length 15"])
+    if ev is None:
+        raise Exception("Invalid CCMP key length not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_gtk_tx_bit_workaround(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: GTK TX bit workaround"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010500dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Tx bit set for GTK, but pairwise keys are used - ignore Tx bit"])
+    if ev is None:
+        raise Exception("GTK Tx bit workaround not reported")
+    dev[0].wait_connected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_gtk_keyidx_0_and_3(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: GTK key index 0 and 3"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4 (GTK keyidx 0)")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010000dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_connected(timeout=1)
+
+    logger.debug("Valid EAPOL-Key group msg 1/2 (GTK keyidx 3)")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('dd16000fac010300dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_info=0x13c2)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    ev = dev[0].wait_event(["WPA: Group rekeying completed"])
+    if ev is None:
+        raise Exception("GTK rekeing not reported")
+
+    logger.debug("Unencrypted GTK KDE in group msg 1/2")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('dd16000fac010300dc11188831bf4aa4a8678d2b41498618')
+    msg = build_eapol_key_3_4(anonce, kck, plain, replay_counter=counter,
+                              key_info=0x03c2)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: GTK IE in unencrypted key data"])
+    if ev is None:
+        raise Exception("Unencrypted GTK KDE not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_no_gtk_in_group_msg(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: GTK KDE missing from group msg"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4 (GTK keyidx 0)")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010000dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_connected(timeout=1)
+
+    logger.debug("No GTK KDE in EAPOL-Key group msg 1/2")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('dd00dd00dd00dd00dd00dd00dd00dd00')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_info=0x13c2)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: No GTK IE in Group Key msg 1/2"])
+    if ev is None:
+        raise Exception("Missing GTK KDE not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_too_long_gtk_in_group_msg(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: too long GTK KDE in group msg"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4 (GTK keyidx 0)")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010000dc11188831bf4aa4a8678d2b41498618')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_connected(timeout=1)
+
+    logger.debug("EAPOL-Key group msg 1/2 with too long GTK KDE")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('dd27000fac010100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter,
+                              key_info=0x13c2)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: Unsupported CCMP Group Cipher key length 33"])
+    if ev is None:
+        raise Exception("Too long GTK KDE not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_too_long_gtk_kde(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: too long GTK KDE"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("EAPOL-Key msg 3/4 with too short GTK KDE")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd27000fac010100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
+    wrapped = aes_wrap(kek, pad_key_data(plain))
+    msg = build_eapol_key_3_4(anonce, kck, wrapped, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    dev[0].wait_disconnected(timeout=1)
+
+def test_ap_wpa2_psk_supp_proto_gtk_not_encrypted(dev, apdev):
+    """WPA2-PSK supplicant protocol testing: GTK KDE not encrypted"""
+    (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
+
+    # Wait for EAPOL-Key msg 1/4 from hostapd to determine when associated
+    msg = recv_eapol(hapd)
+    dev[0].dump_monitor()
+
+    # Build own EAPOL-Key msg 1/4
+    anonce = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
+    counter = 1
+    msg = build_eapol_key_1_4(anonce, replay_counter=counter)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    msg = recv_eapol(dev[0])
+    snonce = msg['rsn_key_nonce']
+
+    (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
+
+    logger.debug("Valid EAPOL-Key msg 3/4")
+    dev[0].dump_monitor()
+    plain = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00dd16000fac010100dc11188831bf4aa4a8678d2b41498618')
+    msg = build_eapol_key_3_4(anonce, kck, plain, replay_counter=counter,
+                              key_info=0x03ca)
+    counter += 1
+    send_eapol(dev[0], addr, build_eapol(msg))
+    ev = dev[0].wait_event(["WPA: GTK IE in unencrypted key data"])
+    if ev is None:
+        raise Exception("Unencrypted GTK KDE not reported")
+    dev[0].wait_disconnected(timeout=1)
+
+def find_wpas_process(dev):
+    ifname = dev.ifname
+    cmd = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE)
+    (data,err) = cmd.communicate()
+    for l in data.splitlines():
+        if "wpa_supplicant" not in l:
+            continue
+        if "-i" + ifname not in l:
+            continue
+        return int(l.strip().split(' ')[0])
+    raise Exception("Could not find wpa_supplicant process")
+
+def read_process_memory(pid, key=None):
+    buf = bytes()
+    with open('/proc/%d/maps' % pid, 'r') as maps, \
+         open('/proc/%d/mem' % pid, 'r') as mem:
+        for l in maps.readlines():
+            m = re.match(r'([0-9a-f]+)-([0-9a-f]+) ([-r][-w][-x][-p])', l)
+            if not m:
+                continue
+            start = int(m.group(1), 16)
+            end = int(m.group(2), 16)
+            perm = m.group(3)
+            if start > 0xffffffffffff:
+                continue
+            if end < start:
+                continue
+            if not perm.startswith('rw'):
+                continue
+            mem.seek(start)
+            data = mem.read(end - start)
+            buf += data
+            if key and key in data:
+                logger.info("Key found in " + l)
+    return buf
+
+def verify_not_present(buf, key, fname, keyname):
+    pos = buf.find(key)
+    if pos < 0:
+        return
+
+    prefix = 2048 if pos > 2048 else pos
+    with open(fname + keyname, 'w') as f:
+        f.write(buf[pos - prefix:pos + 2048])
+    raise Exception(keyname + " found after disassociation")
+
+def get_key_locations(buf, key, keyname):
+    count = 0
+    pos = 0
+    while True:
+        pos = buf.find(key, pos)
+        if pos < 0:
+            break
+        logger.info("Found %s at %d" % (keyname, pos))
+        count += 1
+        pos += len(key)
+    return count
+
+def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
+    """WPA2-PSK and PSK/PTK lifetime in memory"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+    pmk = binascii.unhexlify(psk)
+    p = hostapd.wpa2_params(ssid=ssid)
+    p['wpa_psk'] = psk
+    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+
+    pid = find_wpas_process(dev[0])
+
+    id = dev[0].connect(ssid, raw_psk=psk, scan_freq="2412",
+                        only_add_network=True)
+
+    logger.info("Checking keys in memory after network profile configuration")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+
+    dev[0].request("REMOVE_NETWORK all")
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+
+    id = dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
+                        only_add_network=True)
+
+    logger.info("Checking keys in memory before connection")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+
+    dev[0].connect_network(id, timeout=20)
+    time.sleep(1)
+
+    buf = read_process_memory(pid, pmk)
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    dev[0].relog()
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "WPA: PTK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                ptk = binascii.unhexlify(val)
+            if "WPA: Group Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not pmk or not ptk or not gtk:
+        raise Exception("Could not find keys from debug log")
+    if len(gtk) != 16:
+        raise Exception("Unexpected GTK length")
+
+    kck = ptk[0:16]
+    kek = ptk[16:32]
+    tk = ptk[32:48]
+
+    logger.info("Checking keys in memory while associated")
+    get_key_locations(buf, pmk, "PMK")
+    if pmk not in buf:
+        raise HwsimSkip("PMK not found while associated")
+    if kck not in buf:
+        raise Exception("KCK not found while associated")
+    if kek not in buf:
+        raise Exception("KEK not found while associated")
+    if tk in buf:
+        raise Exception("TK found from memory")
+    if gtk in buf:
+        raise Exception("GTK found from memory")
+
+    logger.info("Checking keys in memory after disassociation")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+
+    # Note: PMK/PSK is still present in network configuration
+
+    fname = os.path.join(params['logdir'],
+                         'wpa2_psk_key_lifetime_in_memory.memctx-')
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+    dev[0].request("REMOVE_NETWORK all")
+
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, pmk)
+    get_key_locations(buf, pmk, "PMK")
+
+    verify_not_present(buf, pmk, fname, "PMK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+def test_ap_wpa2_psk_wep(dev, apdev):
+    """WPA2-PSK AP and WEP enabled"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    try:
+        hapd.set('wep_key0', '"hello"')
+        raise Exception("WEP key accepted to WPA2 network")
+    except Exception:
+        pass
+
+def test_ap_wpa2_psk_wpas_in_bridge(dev, apdev):
+    """WPA2-PSK AP and wpas interface in a bridge"""
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    try:
+        _test_ap_wpa2_psk_wpas_in_bridge(dev, apdev)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
+        subprocess.call(['brctl', 'delif', br_ifname, ifname])
+        subprocess.call(['brctl', 'delbr', br_ifname])
+        subprocess.call(['iw', ifname, 'set', '4addr', 'off'])
+
+def _test_ap_wpa2_psk_wpas_in_bridge(dev, apdev):
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    br_ifname='sta-br0'
+    ifname='wlan5'
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    subprocess.call(['brctl', 'addbr', br_ifname])
+    subprocess.call(['brctl', 'setfd', br_ifname, '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
+    subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
+    subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
+    wpas.interface_add(ifname, br_ifname=br_ifname)
+
+    wpas.connect(ssid, psk=passphrase, scan_freq="2412")
+
+def test_ap_wpa2_psk_ifdown(dev, apdev):
+    """AP with open mode and external ifconfig down"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
+    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
+    ev = hapd.wait_event(["INTERFACE-DISABLED"], timeout=10)
+    if ev is None:
+        raise Exception("No INTERFACE-DISABLED event")
+    # this wait tests beacon loss detection in mac80211
+    dev[0].wait_disconnected()
+    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
+    ev = hapd.wait_event(["INTERFACE-ENABLED"], timeout=10)
+    if ev is None:
+        raise Exception("No INTERFACE-ENABLED event")
+    dev[0].wait_connected()
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_wpa2_psk_drop_first_msg_4(dev, apdev):
+    """WPA2-PSK and first EAPOL-Key msg 4/4 dropped"""
+    bssid = apdev[0]['bssid']
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+    params = hostapd.wpa2_params(ssid=ssid)
+    params['wpa_psk'] = psk
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd.request("SET ext_eapol_frame_io 1")
+    dev[0].request("SET ext_eapol_frame_io 1")
+    dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
+    addr = dev[0].own_addr()
+
+    # EAPOL-Key msg 1/4
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+    res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    # EAPOL-Key msg 2/4
+    ev = dev[0].wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
+    res = hapd.request("EAPOL_RX " + addr + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to hostapd failed")
+
+    # EAPOL-Key msg 3/4
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+    res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    # EAPOL-Key msg 4/4
+    ev = dev[0].wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
+    logger.info("Drop the first EAPOL-Key msg 4/4")
+
+    # wpa_supplicant believes now that 4-way handshake succeeded; hostapd
+    # doesn't. Use normal EAPOL TX/RX to handle retries.
+    hapd.request("SET ext_eapol_frame_io 0")
+    dev[0].request("SET ext_eapol_frame_io 0")
+    dev[0].wait_connected()
+
+    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on AP-STA-CONNECTED from hostapd")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.1)
+    if ev is not None:
+        logger.info("Disconnection detected")
+        # The EAPOL-Key retries are supposed to allow the connection to be
+        # established without having to reassociate. However, this does not
+        # currently work since mac80211 ends up encrypting EAPOL-Key msg 4/4
+        # after the pairwise key has been configured and AP will drop those and
+        # disconnect the station after reaching retransmission limit. Connection
+        # is then established after reassociation. Once that behavior has been
+        # optimized to prevent EAPOL-Key frame encryption for retransmission
+        # case, this exception can be uncommented here.
+        #raise Exception("Unexpected disconnection")
+
+def test_ap_wpa2_psk_disable_enable(dev, apdev):
+    """WPA2-PSK AP getting disabled and re-enabled"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+    params = hostapd.wpa2_params(ssid=ssid)
+    params['wpa_psk'] = psk
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
+
+    for i in range(2):
+        hapd.request("DISABLE")
+        dev[0].wait_disconnected()
+        hapd.request("ENABLE")
+        dev[0].wait_connected()
+        hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_wpa2_psk_incorrect_passphrase(dev, apdev):
+    """WPA2-PSK AP and station using incorrect passphrase"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect(ssid, psk="incorrect passphrase", scan_freq="2412",
+                   wait_connect=False)
+    ev = hapd.wait_event(["AP-STA-POSSIBLE-PSK-MISMATCH"], timeout=10)
+    if ev is None:
+        raise Exception("No AP-STA-POSSIBLE-PSK-MISMATCH reported")
+    dev[0].dump_monitor()
+
+    hapd.disable()
+    hapd.set("wpa_passphrase", "incorrect passphrase")
+    hapd.enable()
+
+    dev[0].wait_connected(timeout=20)
diff --git a/tests/hwsim/test_ap_qosmap.py b/tests/hwsim/test_ap_qosmap.py
index 7a1f8a6..67604b2 100644
--- a/tests/hwsim/test_ap_qosmap.py
+++ b/tests/hwsim/test_ap_qosmap.py
@@ -11,6 +11,7 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
 from wlantest import Wlantest
 
 def check_qos_map(ap, hapd, dev, sta, dscp, tid, ap_tid=None):
@@ -36,7 +37,7 @@
     """QoS mapping"""
     drv_flags = dev[0].get_driver_status_field("capa.flags")
     if int(drv_flags, 0) & 0x40000000 == 0:
-        return "skip"
+        raise HwsimSkip("Driver does not support QoS Map")
     ssid = "test-qosmap"
     params = { "ssid": ssid }
     params['qos_map_set'] = '53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,48,55'
diff --git a/tests/hwsim/test_ap_tdls.py b/tests/hwsim/test_ap_tdls.py
index f4ba292..b2e4586 100644
--- a/tests/hwsim/test_ap_tdls.py
+++ b/tests/hwsim/test_ap_tdls.py
@@ -13,6 +13,7 @@
 from hostapd import HostapdGlobal
 from hostapd import Hostapd
 import hostapd
+from utils import HwsimSkip
 from wlantest import Wlantest
 
 def start_ap_wpa2_psk(ifname):
@@ -304,8 +305,8 @@
         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
         hostapd.add_ap(apdev[1]['ifname'], params)
         wlantest_setup()
-        subprocess.call(['sudo', 'brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
                        bssid=apdev[0]['bssid'])
         dev[1].connect(ssid, psk=passphrase, scan_freq="2412",
@@ -319,8 +320,8 @@
         time.sleep(1)
         hwsim_utils.test_connectivity_sta(dev[0], dev[1])
     finally:
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['sudo', 'brctl', 'delbr', 'ap-br0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'ap-br0'])
 
 def test_ap_wpa2_tdls_responder_teardown(dev, apdev):
     """TDLS teardown from responder with WPA2-PSK AP"""
@@ -355,6 +356,22 @@
         dev[1].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
+
+def test_tdls_chan_switch(dev, apdev):
+    """Open AP and two stations using TDLS"""
+    flags = int(dev[0].get_driver_status_field('capa.flags'), 16)
+    if flags & 0x800000000 == 0:
+        raise HwsimSkip("Driver does not support TDLS channel switching")
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    connect_2sta_open(dev, hapd)
+    setup_tdls(dev[0], dev[1], apdev[0])
+    if "OK" not in dev[0].request("TDLS_CHAN_SWITCH " + dev[1].own_addr() + " 81 2462"):
+        raise Exception("Failed to enable TDLS channel switching")
+    if "OK" not in dev[0].request("TDLS_CANCEL_CHAN_SWITCH " + dev[1].own_addr()):
+        raise Exception("Could not disable TDLS channel switching")
+    if "FAIL" not in dev[0].request("TDLS_CANCEL_CHAN_SWITCH " + dev[1].own_addr()):
+        raise Exception("TDLS_CANCEL_CHAN_SWITCH accepted even though channel switching was already disabled")
diff --git a/tests/hwsim/test_ap_vht.py b/tests/hwsim/test_ap_vht.py
index 235508e..d202598 100644
--- a/tests/hwsim/test_ap_vht.py
+++ b/tests/hwsim/test_ap_vht.py
@@ -12,6 +12,7 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
 from test_dfs import wait_dfs_event
 from test_ap_csa import csa_supported
 
@@ -36,20 +37,23 @@
                    "vht_oper_chwidth": "1",
                    "vht_oper_centr_freq_seg0_idx": "42" }
         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        bssid = apdev[0]['bssid']
 
         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
+        est = dev[0].get_bss(bssid)['est_throughput']
+        if est != "390001":
+            raise Exception("Unexpected BSS est_throughput: " + est)
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
-                logger.info("80 MHz channel not supported in regulatory information")
-                return "skip"
+                raise HwsimSkip("80 MHz channel not supported in regulatory information")
         raise
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_vht80_params(dev, apdev):
@@ -82,15 +86,14 @@
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
-                logger.info("80 MHz channel not supported in regulatory information")
-                return "skip"
+                raise HwsimSkip("80 MHz channel not supported in regulatory information")
         raise
     finally:
         dev[0].request("DISCONNECT")
         dev[1].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
@@ -120,7 +123,7 @@
         dev.request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev.flush_scan_cache()
 
 def test_ap_vht_40(devs, apdevs):
@@ -147,7 +150,7 @@
         dev.request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev.flush_scan_cache()
 
 def test_ap_vht_capab_not_supported(dev, apdev):
@@ -172,7 +175,7 @@
             if "OK" not in hapd.request("SET vht_capab [MAX-A-MPDU-LEN-EXP%d]" % i):
                 raise Exception("Unexpected SET failure")
     finally:
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
 
 def test_ap_vht160(dev, apdev):
     """VHT with 160 MHz channel width"""
@@ -202,7 +205,7 @@
                 # Not all systems have recent enough CRDA version and
                 # wireless-regdb changes to support 160 MHz and DFS. For now,
                 # do not report failures for this test case.
-                return "skip"
+                raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
             raise Exception("Unexpected interface state: " + state)
 
         params = { "ssid": "vht2",
@@ -277,8 +280,7 @@
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
-                logger.info("80/160 MHz channel not supported in regulatory information")
-                return "skip"
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
         raise
     finally:
         dev[0].request("DISCONNECT")
@@ -287,7 +289,7 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
@@ -325,9 +327,12 @@
                    "vht_oper_centr_freq_seg1_idx": "155" }
         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
 
-        ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
+        ev = hapd2.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
         if not ev:
             raise Exception("AP setup timed out(2)")
+        if "AP-DISABLED" in ev:
+            # Assume this failed due to missing regulatory update for now
+            raise HwsimSkip("80+80 MHz channel not supported in regulatory information")
 
         state = hapd2.get_status_field("state")
         if state != "ENABLED":
@@ -347,8 +352,7 @@
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
-                logger.info("80/160 MHz channel not supported in regulatory information")
-                return "skip"
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
         raise
     finally:
         dev[0].request("DISCONNECT")
@@ -357,14 +361,13 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
 def test_ap_vht80_csa(dev, apdev):
     """VHT with 80 MHz channel width and CSA"""
-    if not csa_supported(dev[0]):
-        return "skip"
+    csa_supported(dev[0])
     try:
         hapd = None
         params = { "ssid": "vht",
@@ -406,12 +409,88 @@
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
-                logger.info("80 MHz channel not supported in regulatory information")
-                return "skip"
+                raise HwsimSkip("80 MHz channel not supported in regulatory information")
         raise
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+
+def test_ap_vht_on_24ghz(dev, apdev):
+    """Subset of VHT features on 2.4 GHz"""
+    hapd = None
+    params = { "ssid": "test-vht-2g",
+               "hw_mode": "g",
+               "channel": "1",
+               "ieee80211n": "1",
+               "vendor_vht": "1",
+               "vht_capab": "[MAX-MPDU-11454]",
+               "vht_oper_chwidth": "0",
+               "vht_oper_centr_freq_seg0_idx": "1"
+    }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    try:
+        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd1300904c0400bf0c3240820feaff0000eaff0000"):
+            raise Exception("Failed to add vendor element")
+        dev[0].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
+        hwsim_utils.test_connectivity(dev[0], hapd)
+        sta = hapd.get_sta(dev[0].own_addr())
+        if '[VENDOR_VHT]' not in sta['flags']:
+            raise Exception("No VENDOR_VHT STA flag")
+
+        dev[1].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
+        sta = hapd.get_sta(dev[1].own_addr())
+        if '[VENDOR_VHT]' in sta['flags']:
+            raise Exception("Unexpected VENDOR_VHT STA flag")
+    finally:
+        dev[0].request("VENDOR_ELEM_REMOVE 13 *")
+
+def test_prefer_vht40(dev, apdev):
+    """Preference on VHT40 over HT40"""
+    try:
+        hapd2 = None
+
+        params = { "ssid": "test",
+                   "country_code": "FI",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ieee80211n": "1",
+                   "ht_capab": "[HT40+]" }
+        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        bssid = apdev[0]['bssid']
+
+        params = { "ssid": "test",
+                   "country_code": "FI",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "ht_capab": "[HT40+]",
+                   "vht_capab": "",
+                   "vht_oper_chwidth": "0",
+                   "vht_oper_centr_freq_seg0_idx": "0",
+                 }
+        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        bssid2 = apdev[1]['bssid']
+
+        dev[0].scan_for_bss(bssid, freq=5180)
+        dev[0].scan_for_bss(bssid2, freq=5180)
+        dev[0].connect("test", scan_freq="5180", key_mgmt="NONE")
+        if dev[0].get_status_field('bssid') != bssid2:
+            raise Exception("Unexpected BSS selected")
+
+        est = dev[0].get_bss(bssid)['est_throughput']
+        if est != "135000":
+            raise Exception("Unexpected BSS0 est_throughput: " + est)
+
+        est = dev[0].get_bss(bssid2)['est_throughput']
+        if est != "135001":
+            raise Exception("Unexpected BSS1 est_throughput: " + est)
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd2:
+            hapd2.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
diff --git a/tests/hwsim/test_ap_vlan.py b/tests/hwsim/test_ap_vlan.py
index e70d2de..7b10ea7 100644
--- a/tests/hwsim/test_ap_vlan.py
+++ b/tests/hwsim/test_ap_vlan.py
@@ -80,6 +80,47 @@
     hwsim_utils.test_connectivity_iface(dev[1], hapd, "brvlan2")
     hwsim_utils.test_connectivity(dev[2], hapd)
 
+def test_ap_vlan_wpa2_radius_id_change(dev, apdev):
+    """AP VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID"""
+    as_params = { "ssid": "as",
+                  "beacon_int": "2000",
+                  "radius_server_clients": "auth_serv/radius_clients.conf",
+                  "radius_server_auth_port": '18128',
+                  "eap_server": "1",
+                  "eap_user_file": "auth_serv/eap_user.conf",
+                  "ca_cert": "auth_serv/ca.pem",
+                  "server_cert": "auth_serv/server.pem",
+                  "private_key": "auth_serv/server.key" }
+    authserv = hostapd.add_ap(apdev[1]['ifname'], as_params)
+
+    params = hostapd.wpa2_eap_params(ssid="test-vlan")
+    params['dynamic_vlan'] = "1";
+    params['auth_server_port'] = "18128"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
+                   identity="vlan1",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+
+    authserv.disable()
+    authserv.set('eap_user_file', "auth_serv/eap_user_vlan.conf")
+    authserv.enable()
+
+    dev[0].dump_monitor()
+    dev[0].request("REAUTHENTICATE")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("EAP reauthentication timed out")
+    ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=5)
+    if ev is None:
+        raise Exception("4-way handshake after reauthentication timed out")
+    state = dev[0].get_status_field('wpa_state')
+    if state != "COMPLETED":
+        raise Exception("Unexpected state after reauth: " + state)
+    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
+
 def test_ap_vlan_wpa2_radius_required(dev, apdev):
     """AP VLAN with WPA2-Enterprise and RADIUS attributes required"""
     params = hostapd.wpa2_eap_params(ssid="test-vlan")
diff --git a/tests/hwsim/test_ap_wps.py b/tests/hwsim/test_ap_wps.py
index 70ef48f..8b29be9 100644
--- a/tests/hwsim/test_ap_wps.py
+++ b/tests/hwsim/test_ap_wps.py
@@ -20,6 +20,7 @@
 import hwsim_utils
 import hostapd
 from wpasupplicant import WpaSupplicant
+from utils import HwsimSkip
 
 def test_ap_wps_init(dev, apdev):
     """Initial AP configuration with first WPS Enrollee"""
@@ -215,7 +216,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_wps_conf_chan14(dev, apdev):
@@ -240,7 +241,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_wps_twice(dev, apdev):
@@ -455,6 +456,27 @@
     if status['key_mgmt'] != 'WPA2-PSK':
         raise Exception("Unexpected key_mgmt")
 
+def test_ap_wps_reg_connect_mixed_mode(dev, apdev):
+    """WPS registrar using AP PIN to connect (WPA+WPA2)"""
+    ssid = "test-wps-reg-ap-pin"
+    appin = "12345670"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                     "wpa_passphrase": "12345678", "wpa": "3",
+                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                     "wpa_pairwise": "TKIP", "ap_pin": appin})
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
+    dev[0].wps_reg(apdev[0]['bssid'], appin)
+    status = dev[0].get_status()
+    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']:
+        raise Exception("Not fully connected")
+    if status['ssid'] != ssid:
+        raise Exception("Unexpected SSID")
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'TKIP':
+        raise Exception("Unexpected encryption configuration")
+    if status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected key_mgmt")
+
 def check_wps_reg_failure(dev, ap, appin):
     dev.request("WPS_REG " + ap['bssid'] + " " + appin)
     ev = dev.wait_event(["WPS-SUCCESS", "WPS-FAIL"], timeout=15)
@@ -1033,6 +1055,11 @@
     dev[0].dump_monitor()
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
 
+    dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[2].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    # avoid leaving dev 1 or 2 as the last Probe Request to the AP
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412, force_scan=True)
+
     dev[0].dump_monitor()
     dev[0].request("WPS_ER_START ifname=lo")
 
@@ -1046,8 +1073,7 @@
     if "FAIL" in dev[0].request("WPS_ER_SET_CONFIG " + apdev[0]['bssid'] + " 0"):
         raise Exception("Could not select AP based on BSSID")
 
-    dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
-    dev[2].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
     dev[1].request("WPS_PBC " + apdev[0]['bssid'])
     dev[2].request("WPS_PBC " + apdev[0]['bssid'])
     ev = dev[1].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
@@ -1056,10 +1082,22 @@
     ev = dev[2].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
     if ev is None:
         raise Exception("PBC scan failed")
-    for i in range(0, 2):
+    found1 = False
+    found2 = False
+    addr1 = dev[1].own_addr()
+    addr2 = dev[2].own_addr()
+    for i in range(3):
         ev = dev[0].wait_event(["WPS-ER-ENROLLEE-ADD"], timeout=15)
         if ev is None:
             raise Exception("Enrollee discovery timed out")
+        if addr1 in ev:
+            found1 = True
+            if found2:
+                break
+        if addr2 in ev:
+            found2 = True
+            if found1:
+                break
     if dev[0].request("WPS_ER_PBC " + ap_uuid) != "FAIL-PBC-OVERLAP\n":
         raise Exception("PBC overlap not reported")
     dev[1].request("WPS_CANCEL")
@@ -1381,9 +1419,9 @@
 
 def test_ap_wps_per_station_psk(dev, apdev):
     """WPS PBC provisioning with per-station PSK"""
-    addr0 = dev[0].p2p_dev_addr()
-    addr1 = dev[1].p2p_dev_addr()
-    addr2 = dev[2].p2p_dev_addr()
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    addr2 = dev[2].own_addr()
     ssid = "wps"
     appin = "12345670"
     pskfile = "/tmp/ap_wps_per_enrollee_psk.psk_file"
@@ -1498,7 +1536,7 @@
     ssid = "wps"
     pinfile = "/tmp/ap_wps_pin_request_file.log"
     if os.path.exists(pinfile):
-        subprocess.call(['sudo', 'rm', pinfile])
+        os.remove(pinfile)
     hostapd.add_ap(apdev[0]['ifname'],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wps_pin_requests": pinfile,
@@ -1526,7 +1564,10 @@
         if not success:
             raise Exception("PIN request entry not in the log file")
     finally:
-        subprocess.call(['sudo', 'rm', pinfile])
+        try:
+            os.remove(pinfile)
+        except:
+            pass
 
 def test_ap_wps_auto_setup_with_config_file(dev, apdev):
     """WPS auto-setup with configuration file"""
@@ -1564,13 +1605,15 @@
         if vals['ieee80211n'] != '1' or vals['wps_state'] != '2' or "WPA-PSK" not in vals['wpa_key_mgmt']:
             raise Exception("Incorrect configuration: " + str(vals))
     finally:
-        subprocess.call(['sudo', 'rm', conffile])
+        try:
+            os.remove(conffile)
+        except:
+            pass
 
 def test_ap_wps_pbc_timeout(dev, apdev, params):
     """wpa_supplicant PBC walk time [long]"""
     if not params['long']:
-        logger.info("Skip test case with long duration due to --long not specified")
-        return "skip"
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
     ssid = "test-wps"
     hostapd.add_ap(apdev[0]['ifname'],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
@@ -2309,3 +2352,65 @@
     wpas.dump_monitor()
     wpas.request("REASSOCIATE")
     wpas.wait_connected(timeout=30)
+
+def test_ap_wps_eapol_workaround(dev, apdev):
+    """EAPOL workaround code path for 802.1X header length mismatch"""
+    ssid = "test-wps"
+    hostapd.add_ap(apdev[0]['ifname'],
+                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    bssid = apdev[0]['bssid']
+    hapd.request("SET ext_eapol_frame_io 1")
+    dev[0].request("SET ext_eapol_frame_io 1")
+    hapd.request("WPS_PBC")
+    dev[0].request("WPS_PBC")
+
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+
+    res = dev[0].request("EAPOL_RX " + bssid + " 020000040193000501FFFF")
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+def test_ap_wps_iteration(dev, apdev):
+    """WPS PIN and iterate through APs without selected registrar"""
+    ssid = "test-wps-conf"
+    hapd = hostapd.add_ap(apdev[0]['ifname'],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
+
+    ssid2 = "test-wps-conf2"
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'],
+                           { "ssid": ssid2, "eap_server": "1", "wps_state": "2",
+                             "wpa_passphrase": "12345678", "wpa": "2",
+                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
+
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+    pin = dev[0].request("WPS_PIN any")
+
+    # Wait for iteration through all WPS APs to happen before enabling any
+    # Registrar.
+    for i in range(2):
+        ev = dev[0].wait_event(["Associated with"], timeout=30)
+        if ev is None:
+            raise Exception("No association seen")
+        ev = dev[0].wait_event(["WPS-M2D"], timeout=10)
+        if ev is None:
+            raise Exception("No M2D from AP")
+        dev[0].wait_disconnected()
+
+    # Verify that each AP requested PIN
+    ev = hapd.wait_event(["WPS-PIN-NEEDED"], timeout=1)
+    if ev is None:
+        raise Exception("No WPS-PIN-NEEDED event from AP")
+    ev = hapd2.wait_event(["WPS-PIN-NEEDED"], timeout=1)
+    if ev is None:
+        raise Exception("No WPS-PIN-NEEDED event from AP2")
+
+    # Provide PIN to one of the APs and verify that connection gets formed
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].wait_connected(timeout=30)
diff --git a/tests/hwsim/test_bgscan.py b/tests/hwsim/test_bgscan.py
index 1ae4a2a..c73fdeb 100644
--- a/tests/hwsim/test_bgscan.py
+++ b/tests/hwsim/test_bgscan.py
@@ -21,6 +21,26 @@
     dev[1].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
                    bgscan="simple:1:-45:2")
 
+    dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                   bgscan="simple:1:-45")
+    dev[2].request("REMOVE_NETWORK all")
+    dev[2].wait_disconnected()
+
+    dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                   bgscan="simple:0:0")
+    dev[2].request("REMOVE_NETWORK all")
+    dev[2].wait_disconnected()
+
+    dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                   bgscan="simple")
+    dev[2].request("REMOVE_NETWORK all")
+    dev[2].wait_disconnected()
+
+    dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                   bgscan="simple:1")
+    dev[2].request("REMOVE_NETWORK all")
+    dev[2].wait_disconnected()
+
     ev = dev[0].wait_event(["CTRL-EVENT-SIGNAL-CHANGE"], timeout=10)
     if ev is None:
         raise Exception("dev0 did not indicate signal change event")
@@ -61,8 +81,28 @@
     try:
         dev[0].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
                        bgscan="learn:1:-20:2")
-        dev[1].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
-                       bgscan="learn:1:-45:2:/tmp/test_bgscan_learn.bgscan")
+        id = dev[1].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                            bgscan="learn:1:-45:2:/tmp/test_bgscan_learn.bgscan")
+
+        dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                       bgscan="learn:1:-45")
+        dev[2].request("REMOVE_NETWORK all")
+        dev[2].wait_disconnected()
+
+        dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                       bgscan="learn:0:0")
+        dev[2].request("REMOVE_NETWORK all")
+        dev[2].wait_disconnected()
+
+        dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                       bgscan="learn")
+        dev[2].request("REMOVE_NETWORK all")
+        dev[2].wait_disconnected()
+
+        dev[2].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
+                       bgscan="learn:1")
+        dev[2].request("REMOVE_NETWORK all")
+        dev[2].wait_disconnected()
 
         ev = dev[0].wait_event(["CTRL-EVENT-SIGNAL-CHANGE"], timeout=10)
         if ev is None:
@@ -94,7 +134,6 @@
         dev[0].request("DISCONNECT")
         dev[1].request("DISCONNECT")
         dev[0].request("REMOVE_NETWORK all")
-        dev[1].request("REMOVE_NETWORK all")
 
         with open("/tmp/test_bgscan_learn.bgscan", "r") as f:
             lines = f.read().splitlines()
@@ -108,6 +147,19 @@
             raise Exception("Missing BSS1->BSS2 neighbor entry")
         if 'NEIGHBOR 02:00:00:00:04:00 02:00:00:00:03:00' not in lines:
             raise Exception("Missing BSS2->BSS1 neighbor entry")
+
+        dev[1].set_network(id, "scan_freq", "")
+        dev[1].connect_network(id)
+
+        ev = dev[1].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("dev1 did not start a scan")
+
+        ev = dev[1].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
+        if ev is None:
+            raise Exception("dev1 did not complete a scan")
+
+        dev[1].request("REMOVE_NETWORK all")
     finally:
         try:
             os.remove("/tmp/test_bgscan_learn.bgscan")
diff --git a/tests/hwsim/test_cfg80211.py b/tests/hwsim/test_cfg80211.py
index 239b510..e67ad98 100644
--- a/tests/hwsim/test_cfg80211.py
+++ b/tests/hwsim/test_cfg80211.py
@@ -13,6 +13,7 @@
 
 import hostapd
 import hwsim_utils
+from tshark import run_tshark
 from nl80211 import *
 
 def nl80211_command(dev, cmd, attr):
@@ -82,28 +83,9 @@
     # note: also the Deauthenticate frame sent by the GO going down ends up
     # being transmitted incorrectly on 2422 MHz.
 
-    try:
-        arg = [ "tshark",
-                "-r", os.path.join(params['logdir'], "hwsim0.pcapng"),
-                "-Y", "wlan.fc.type_subtype == 13",
-                "-Tfields", "-e", "radiotap.channel.freq" ]
-        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
-                               stderr=open('/dev/null', 'w'))
-    except Exception, e:
-        logger.info("Could run run tshark check: " + str(e))
-        cmd = None
-        pass
-
-    if cmd:
-        (out,err) = cmd.communicate()
-        res = cmd.wait()
-        if res == 1:
-            arg[3] = '-R'
-            cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
-                                   stderr=open('/dev/null', 'w'))
-            (out,err) = cmd.communicate()
-            res = cmd.wait()
-
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan.fc.type_subtype == 13", ["radiotap.channel.freq"])
+    if out is not None:
         freq = out.splitlines()
         if len(freq) != 2:
             raise Exception("Unexpected number of Action frames (%d)" % len(freq))
@@ -140,3 +122,22 @@
     # the previous command results in deauth event followed by auto-reconnect
     dev[0].wait_connected(timeout=10, error="Reassociation timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_cfg80211_hostapd_ext_sta_remove(dev, apdev):
+    """cfg80211 DEL_STATION issued externally to hostapd"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'],
+                          { "ssid": "open" })
+    id = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+
+    ifindex = int(hapd.get_driver_status_field("ifindex"))
+    attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
+    attrs += build_nl80211_attr_u16('REASON_CODE', 1)
+    attrs += build_nl80211_attr_u8('MGMT_SUBTYPE', 12)
+    attrs += build_nl80211_attr_mac('MAC', dev[0].own_addr())
+    nl80211_command(hapd, 'DEL_STATION', attrs)
+
+    # Currently, hostapd ignores the NL80211_CMD_DEL_STATION event if
+    # drv->device_ap_sme == 0 (which is the case with mac80211_hwsim), so no
+    # further action happens here. If that event were to be used to remove the
+    # STA entry from hostapd even in device_ap_sme == 0 case, this test case
+    # could be extended to cover additional operations.
diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py
new file mode 100644
index 0000000..7ec3114
--- /dev/null
+++ b/tests/hwsim/test_dbus.py
@@ -0,0 +1,4262 @@
+# wpa_supplicant D-Bus interface tests
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import binascii
+import logging
+logger = logging.getLogger()
+import subprocess
+import time
+
+try:
+    import gobject
+    import dbus
+    dbus_imported = True
+except ImportError:
+    dbus_imported = False
+
+import hostapd
+from wpasupplicant import WpaSupplicant
+from utils import HwsimSkip, alloc_fail
+from test_ap_tdls import connect_2sta_open
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_PATH = "/fi/w1/wpa_supplicant1"
+WPAS_DBUS_IFACE = "fi.w1.wpa_supplicant1.Interface"
+WPAS_DBUS_IFACE_WPS = WPAS_DBUS_IFACE + ".WPS"
+WPAS_DBUS_NETWORK = "fi.w1.wpa_supplicant1.Network"
+WPAS_DBUS_BSS = "fi.w1.wpa_supplicant1.BSS"
+WPAS_DBUS_IFACE_P2PDEVICE = WPAS_DBUS_IFACE + ".P2PDevice"
+WPAS_DBUS_P2P_PEER = "fi.w1.wpa_supplicant1.Peer"
+WPAS_DBUS_GROUP = "fi.w1.wpa_supplicant1.Group"
+WPAS_DBUS_PERSISTENT_GROUP = "fi.w1.wpa_supplicant1.PersistentGroup"
+
+def prepare_dbus(dev):
+    if not dbus_imported:
+        logger.info("No dbus module available")
+        raise HwsimSkip("No dbus module available")
+    try:
+        from dbus.mainloop.glib import DBusGMainLoop
+        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+        bus = dbus.SystemBus()
+        wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH)
+        wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
+        path = wpas.GetInterface(dev.ifname)
+        if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+        return (bus,wpas_obj,path,if_obj)
+    except Exception, e:
+        raise HwsimSkip("Could not connect to D-Bus: %s" % e)
+
+class TestDbus(object):
+    def __init__(self, bus):
+        self.loop = gobject.MainLoop()
+        self.signals = []
+        self.bus = bus
+
+    def __exit__(self, type, value, traceback):
+        for s in self.signals:
+            s.remove()
+
+    def add_signal(self, handler, interface, name, byte_arrays=False):
+        s = self.bus.add_signal_receiver(handler, dbus_interface=interface,
+                                         signal_name=name,
+                                         byte_arrays=byte_arrays)
+        self.signals.append(s)
+
+    def timeout(self, *args):
+        logger.debug("timeout")
+        self.loop.quit()
+        return False
+
+class alloc_fail_dbus(object):
+    def __init__(self, dev, count, funcs, operation="Operation",
+                 expected="NoMemory"):
+        self._dev = dev
+        self._count = count
+        self._funcs = funcs
+        self._operation = operation
+        self._expected = expected
+    def __enter__(self):
+        cmd = "TEST_ALLOC_FAIL %d:%s" % (self._count, self._funcs)
+        if "OK" not in self._dev.request(cmd):
+            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
+    def __exit__(self, type, value, traceback):
+        if type is None:
+            raise Exception("%s succeeded during out-of-memory" % self._operation)
+        if type == dbus.exceptions.DBusException and self._expected in str(value):
+            return True
+        if self._dev.request("GET_ALLOC_FAIL") != "0:%s" % self._funcs:
+            raise Exception("%s did not trigger allocation failure" % self._operation)
+        return False
+
+def start_ap(ap):
+    ssid = "test-wps"
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "ap_pin": "12345670"}
+    return hostapd.add_ap(ap['ifname'], params)
+
+def test_dbus_getall(dev, apdev):
+    """D-Bus GetAll"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    props = wpas_obj.GetAll(WPAS_DBUS_SERVICE,
+                            dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(fi.w1.wpa.supplicant1, /fi/w1/wpa_supplicant1) ==> " + str(props))
+
+    props = if_obj.GetAll(WPAS_DBUS_IFACE,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_IFACE, path, str(props)))
+
+    props = if_obj.GetAll(WPAS_DBUS_IFACE_WPS,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_IFACE_WPS, path, str(props)))
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 0:
+        raise Exception("Unexpected BSSs entry: " + str(res))
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 0:
+        raise Exception("Unexpected Networks entry: " + str(res))
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq=2412)
+    id = dev[0].add_network()
+    dev[0].set_network(id, "disabled", "0")
+    dev[0].set_network_quoted(id, "ssid", "test")
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 1:
+        raise Exception("Missing BSSs entry: " + str(res))
+    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
+    props = bss_obj.GetAll(WPAS_DBUS_BSS, dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_BSS, res[0], str(props)))
+    bssid_str = ''
+    for item in props['BSSID']:
+        if len(bssid_str) > 0:
+            bssid_str += ':'
+        bssid_str += '%02x' % item
+    if bssid_str != bssid:
+        raise Exception("Unexpected BSSID in BSSs entry")
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 1:
+        raise Exception("Missing Networks entry: " + str(res))
+    net_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
+    props = net_obj.GetAll(WPAS_DBUS_NETWORK,
+                           dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_NETWORK, res[0], str(props)))
+    ssid = props['Properties']['ssid']
+    if ssid != '"test"':
+        raise Exception("Unexpected SSID in network entry")
+
+def dbus_get(dbus, wpas_obj, prop, expect=None, byte_arrays=False):
+    val = wpas_obj.Get(WPAS_DBUS_SERVICE, prop,
+                       dbus_interface=dbus.PROPERTIES_IFACE,
+                       byte_arrays=byte_arrays)
+    if expect is not None and val != expect:
+        raise Exception("Unexpected %s: %s (expected: %s)" %
+                        (prop, str(val), str(expect)))
+    return val
+
+def dbus_set(dbus, wpas_obj, prop, val):
+    wpas_obj.Set(WPAS_DBUS_SERVICE, prop, val,
+                 dbus_interface=dbus.PROPERTIES_IFACE)
+
+def test_dbus_properties(dev, apdev):
+    """D-Bus Get/Set fi.w1.wpa_supplicant1 properties"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    dbus_get(dbus, wpas_obj, "DebugLevel", expect="msgdump")
+    dbus_set(dbus, wpas_obj, "DebugLevel", "debug")
+    dbus_get(dbus, wpas_obj, "DebugLevel", expect="debug")
+    for (val,err) in [ (3, "Error.Failed: wrong property type"),
+                       ("foo", "Error.Failed: wrong debug level value") ]:
+        try:
+            dbus_set(dbus, wpas_obj, "DebugLevel", val)
+            raise Exception("Invalid DebugLevel value accepted: " + str(val))
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message: " + str(e))
+    dbus_set(dbus, wpas_obj, "DebugLevel", "msgdump")
+    dbus_get(dbus, wpas_obj, "DebugLevel", expect="msgdump")
+
+    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=True)
+    dbus_set(dbus, wpas_obj, "DebugTimestamp", False)
+    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=False)
+    try:
+        dbus_set(dbus, wpas_obj, "DebugTimestamp", "foo")
+        raise Exception("Invalid DebugTimestamp value accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+    dbus_set(dbus, wpas_obj, "DebugTimestamp", True)
+    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=True)
+
+    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=True)
+    dbus_set(dbus, wpas_obj, "DebugShowKeys", False)
+    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=False)
+    try:
+        dbus_set(dbus, wpas_obj, "DebugShowKeys", "foo")
+        raise Exception("Invalid DebugShowKeys value accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+    dbus_set(dbus, wpas_obj, "DebugShowKeys", True)
+    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=True)
+
+    res = dbus_get(dbus, wpas_obj, "Interfaces")
+    if len(res) != 1:
+        raise Exception("Unexpected Interfaces value: " + str(res))
+
+    res = dbus_get(dbus, wpas_obj, "EapMethods")
+    if len(res) < 5 or "TTLS" not in res:
+        raise Exception("Unexpected EapMethods value: " + str(res))
+
+    res = dbus_get(dbus, wpas_obj, "Capabilities")
+    if len(res) < 2 or "p2p" not in res:
+        raise Exception("Unexpected Capabilities value: " + str(res))
+
+    dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
+    val = binascii.unhexlify("010006020304050608")
+    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(val))
+    res = dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
+    if val != res:
+        raise Exception("WFDIEs value changed")
+    try:
+        dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray('\x00'))
+        raise Exception("Invalid WFDIEs value accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(''))
+    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(val))
+    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(''))
+    res = dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
+    if len(res) != 0:
+        raise Exception("WFDIEs not cleared properly")
+
+    res = dbus_get(dbus, wpas_obj, "EapMethods")
+    try:
+        dbus_set(dbus, wpas_obj, "EapMethods", res)
+        raise Exception("Invalid Set accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: Property is read-only" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    try:
+        wpas_obj.SetFoo(WPAS_DBUS_SERVICE, "DebugShowKeys", True,
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Unknown method accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownMethod" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    try:
+        wpas_obj.Get("foo", "DebugShowKeys",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Get accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: No such property" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    test_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH,
+                              introspect=False)
+    try:
+        test_obj.Get(123, "DebugShowKeys",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Get accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: Invalid arguments" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+    try:
+        test_obj.Get(WPAS_DBUS_SERVICE, 123,
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Get accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: Invalid arguments" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    try:
+        wpas_obj.Set(WPAS_DBUS_SERVICE, "WFDIEs",
+                     dbus.ByteArray('', variant_level=2),
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: invalid message format" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+def test_dbus_invalid_method(dev, apdev):
+    """D-Bus invalid method"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    try:
+        wps.Foo()
+        raise Exception("Unknown method accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownMethod" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    test_obj = bus.get_object(WPAS_DBUS_SERVICE, path, introspect=False)
+    test_wps = dbus.Interface(test_obj, WPAS_DBUS_IFACE_WPS)
+    try:
+        test_wps.Start(123)
+        raise Exception("WPS.Start with incorrect signature accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs: Invalid arg" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+def test_dbus_get_set_wps(dev, apdev):
+    """D-Bus Get/Set for WPS properties"""
+    try:
+        _test_dbus_get_set_wps(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+        dev[0].request("SET config_methods display keypad virtual_display nfc_interface p2ps")
+
+def _test_dbus_get_set_wps(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+    val = "display keypad virtual_display nfc_interface"
+    dev[0].request("SET config_methods " + val)
+
+    config = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+    if config != val:
+        raise Exception("Unexpected Get(ConfigMethods) result: " + config)
+
+    val2 = "push_button display"
+    if_obj.Set(WPAS_DBUS_IFACE_WPS, "ConfigMethods", val2,
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    config = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+    if config != val2:
+        raise Exception("Unexpected Get(ConfigMethods) result after Set: " + config)
+
+    dev[0].request("SET config_methods " + val)
+
+    for i in range(3):
+        dev[0].request("SET wps_cred_processing " + str(i))
+        val = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
+                         dbus_interface=dbus.PROPERTIES_IFACE)
+        expected_val = False if i == 1 else True
+        if val != expected_val:
+            raise Exception("Unexpected Get(ProcessCredentials) result({}): {}".format(i, val))
+
+    class TestDbusGetSet(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.signal_received = False
+            self.signal_received_deprecated = False
+            self.sets_done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_sets)
+            gobject.timeout_add(1000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE_WPS,
+                            "PropertiesChanged")
+            self.add_signal(self.propertiesChanged2, dbus.PROPERTIES_IFACE,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("PropertiesChanged: " + str(properties))
+            if properties.has_key("ProcessCredentials"):
+                self.signal_received_deprecated = True
+                if self.sets_done and self.signal_received:
+                    self.loop.quit()
+
+        def propertiesChanged2(self, interface_name, changed_properties,
+                               invalidated_properties):
+            logger.debug("propertiesChanged2: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
+            if interface_name != WPAS_DBUS_IFACE_WPS:
+                return
+            if changed_properties.has_key("ProcessCredentials"):
+                self.signal_received = True
+                if self.sets_done and self.signal_received_deprecated:
+                    self.loop.quit()
+
+        def run_sets(self, *args):
+            logger.debug("run_sets")
+            if_obj.Set(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
+                       dbus.Boolean(1),
+                       dbus_interface=dbus.PROPERTIES_IFACE)
+            if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
+                          dbus_interface=dbus.PROPERTIES_IFACE) != True:
+                raise Exception("Unexpected Get(ProcessCredentials) result after Set");
+            if_obj.Set(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
+                       dbus.Boolean(0),
+                       dbus_interface=dbus.PROPERTIES_IFACE)
+            if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
+                          dbus_interface=dbus.PROPERTIES_IFACE) != False:
+                raise Exception("Unexpected Get(ProcessCredentials) result after Set");
+
+            self.dbus_sets_done = True
+            return False
+
+        def success(self):
+            return self.signal_received and self.signal_received_deprecated
+
+    with TestDbusGetSet(bus) as t:
+        if not t.success():
+            raise Exception("No signal received for ProcessCredentials change")
+
+def test_dbus_wps_invalid(dev, apdev):
+    """D-Bus invaldi WPS operation"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    failures = [ {'Role': 'foo', 'Type': 'pbc'},
+                 {'Role': 123, 'Type': 'pbc'},
+                 {'Type': 'pbc'},
+                 {'Role': 'enrollee'},
+                 {'Role': 'registrar'},
+                 {'Role': 'enrollee', 'Type': 123},
+                 {'Role': 'enrollee', 'Type': 'foo'},
+                 {'Role': 'enrollee', 'Type': 'pbc',
+                  'Bssid': '02:33:44:55:66:77'},
+                 {'Role': 'enrollee', 'Type': 'pin', 'Pin': 123},
+                 {'Role': 'enrollee', 'Type': 'pbc',
+                  'Bssid': dbus.ByteArray('12345')},
+                 {'Role': 'enrollee', 'Type': 'pbc',
+                  'P2PDeviceAddress': 12345},
+                 {'Role': 'enrollee', 'Type': 'pbc',
+                  'P2PDeviceAddress': dbus.ByteArray('12345')},
+                 {'Role': 'enrollee', 'Type': 'pbc', 'Foo': 'bar'} ]
+    for args in failures:
+        try:
+            wps.Start(args)
+            raise Exception("Invalid WPS.Start() arguments accepted: " + str(args))
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.w1.wpa_supplicant1.InvalidArgs"):
+                raise Exception("Unexpected error message: " + str(e))
+
+def test_dbus_wps_oom(dev, apdev):
+    """D-Bus WPS operation (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_getter_state", "Get"):
+        if_obj.Get(WPAS_DBUS_IFACE, "State",
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq=2412)
+
+    for i in range(1, 3):
+        with alloc_fail_dbus(dev[0], i, "=wpas_dbus_getter_bsss", "Get"):
+            if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
+                       dbus_interface=dbus.PROPERTIES_IFACE)
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
+    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_getter_bss_rates", "Get"):
+        bss_obj.Get(WPAS_DBUS_BSS, "Rates",
+                    dbus_interface=dbus.PROPERTIES_IFACE)
+
+    id = dev[0].add_network()
+    dev[0].set_network(id, "disabled", "0")
+    dev[0].set_network_quoted(id, "ssid", "test")
+
+    for i in range(1, 3):
+        with alloc_fail_dbus(dev[0], i, "=wpas_dbus_getter_networks", "Get"):
+            if_obj.Get(WPAS_DBUS_IFACE, "Networks",
+                       dbus_interface=dbus.PROPERTIES_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_getter_interfaces", "Get"):
+        dbus_get(dbus, wpas_obj, "Interfaces")
+
+    for i in range(1, 6):
+        with alloc_fail_dbus(dev[0], i, "=eap_get_names_as_string_array;wpas_dbus_getter_eap_methods", "Get"):
+            dbus_get(dbus, wpas_obj, "EapMethods")
+
+    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_setter_config_methods", "Set",
+                         expected="Error.Failed: Failed to set property"):
+        val2 = "push_button display"
+        if_obj.Set(WPAS_DBUS_IFACE_WPS, "ConfigMethods", val2,
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "=wpa_config_add_network;wpas_dbus_handler_wps_start",
+                         "WPS.Start",
+                         expected="UnknownError: WPS start failed"):
+        wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670'})
+
+def test_dbus_wps_pbc(dev, apdev):
+    """D-Bus WPS/PBC operation and signals"""
+    try:
+        _test_dbus_wps_pbc(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_wps_pbc(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    hapd = start_ap(apdev[0])
+    hapd.request("WPS_PBC")
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 1:
+        raise Exception("Missing BSSs entry: " + str(res))
+    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
+    props = bss_obj.GetAll(WPAS_DBUS_BSS, dbus_interface=dbus.PROPERTIES_IFACE)
+    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_BSS, res[0], str(props)))
+    if 'WPS' not in props:
+        raise Exception("No WPS information in the BSS entry")
+    if 'Type' not in props['WPS']:
+        raise Exception("No Type field in the WPS dictionary")
+    if props['WPS']['Type'] != 'pbc':
+        raise Exception("Unexpected WPS Type: " + props['WPS']['Type'])
+
+    class TestDbusWps(TestDbus):
+        def __init__(self, bus, wps):
+            TestDbus.__init__(self, bus)
+            self.success_seen = False
+            self.credentials_received = False
+            self.wps = wps
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.start_pbc)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
+            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
+                            "Credentials")
+            self.loop.run()
+            return self
+
+        def wpsEvent(self, name, args):
+            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
+            if name == "success":
+                self.success_seen = True
+                if self.credentials_received:
+                    self.loop.quit()
+
+        def credentials(self, args):
+            logger.debug("credentials: " + str(args))
+            self.credentials_received = True
+            if self.success_seen:
+                self.loop.quit()
+
+        def start_pbc(self, *args):
+            logger.debug("start_pbc")
+            self.wps.Start({'Role': 'enrollee', 'Type': 'pbc'})
+            return False
+
+        def success(self):
+            return self.success_seen and self.credentials_received
+
+    with TestDbusWps(bus, wps) as t:
+        if not t.success():
+            raise Exception("Failure in D-Bus operations")
+
+    dev[0].wait_connected(timeout=10)
+    dev[0].request("DISCONNECT")
+    hapd.disable()
+    dev[0].flush_scan_cache()
+
+def test_dbus_wps_pin(dev, apdev):
+    """D-Bus WPS/PIN operation and signals"""
+    try:
+        _test_dbus_wps_pin(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_wps_pin(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    hapd = start_ap(apdev[0])
+    hapd.request("WPS_PIN any 12345670")
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    class TestDbusWps(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.success_seen = False
+            self.credentials_received = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.start_pin)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
+            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
+                            "Credentials")
+            self.loop.run()
+            return self
+
+        def wpsEvent(self, name, args):
+            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
+            if name == "success":
+                self.success_seen = True
+                if self.credentials_received:
+                    self.loop.quit()
+
+        def credentials(self, args):
+            logger.debug("credentials: " + str(args))
+            self.credentials_received = True
+            if self.success_seen:
+                self.loop.quit()
+
+        def start_pin(self, *args):
+            logger.debug("start_pin")
+            bssid_ay = dbus.ByteArray(bssid.replace(':','').decode('hex'))
+            wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670',
+                       'Bssid': bssid_ay})
+            return False
+
+        def success(self):
+            return self.success_seen and self.credentials_received
+
+    with TestDbusWps(bus) as t:
+        if not t.success():
+            raise Exception("Failure in D-Bus operations")
+
+    dev[0].wait_connected(timeout=10)
+
+def test_dbus_wps_pin2(dev, apdev):
+    """D-Bus WPS/PIN operation and signals (PIN from wpa_supplicant)"""
+    try:
+        _test_dbus_wps_pin2(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_wps_pin2(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    class TestDbusWps(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.success_seen = False
+            self.failed = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.start_pin)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
+            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
+                            "Credentials")
+            self.loop.run()
+            return self
+
+        def wpsEvent(self, name, args):
+            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
+            if name == "success":
+                self.success_seen = True
+                if self.credentials_received:
+                    self.loop.quit()
+
+        def credentials(self, args):
+            logger.debug("credentials: " + str(args))
+            self.credentials_received = True
+            if self.success_seen:
+                self.loop.quit()
+
+        def start_pin(self, *args):
+            logger.debug("start_pin")
+            bssid_ay = dbus.ByteArray(bssid.replace(':','').decode('hex'))
+            res = wps.Start({'Role': 'enrollee', 'Type': 'pin',
+                             'Bssid': bssid_ay})
+            pin = res['Pin']
+            h = hostapd.Hostapd(apdev[0]['ifname'])
+            h.request("WPS_PIN any " + pin)
+            return False
+
+        def success(self):
+            return self.success_seen and self.credentials_received
+
+    with TestDbusWps(bus) as t:
+        if not t.success():
+            raise Exception("Failure in D-Bus operations")
+
+    dev[0].wait_connected(timeout=10)
+
+def test_dbus_wps_pin_m2d(dev, apdev):
+    """D-Bus WPS/PIN operation and signals with M2D"""
+    try:
+        _test_dbus_wps_pin_m2d(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_wps_pin_m2d(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    class TestDbusWps(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.success_seen = False
+            self.credentials_received = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.start_pin)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
+            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
+                            "Credentials")
+            self.loop.run()
+            return self
+
+        def wpsEvent(self, name, args):
+            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
+            if name == "success":
+                self.success_seen = True
+                if self.credentials_received:
+                    self.loop.quit()
+            elif name == "m2d":
+                h = hostapd.Hostapd(apdev[0]['ifname'])
+                h.request("WPS_PIN any 12345670")
+
+        def credentials(self, args):
+            logger.debug("credentials: " + str(args))
+            self.credentials_received = True
+            if self.success_seen:
+                self.loop.quit()
+
+        def start_pin(self, *args):
+            logger.debug("start_pin")
+            bssid_ay = dbus.ByteArray(bssid.replace(':','').decode('hex'))
+            wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670',
+                       'Bssid': bssid_ay})
+            return False
+
+        def success(self):
+            return self.success_seen and self.credentials_received
+
+    with TestDbusWps(bus) as t:
+        if not t.success():
+            raise Exception("Failure in D-Bus operations")
+
+    dev[0].wait_connected(timeout=10)
+
+def test_dbus_wps_reg(dev, apdev):
+    """D-Bus WPS/Registrar operation and signals"""
+    try:
+        _test_dbus_wps_reg(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_wps_reg(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    hapd = start_ap(apdev[0])
+    hapd.request("WPS_PIN any 12345670")
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    class TestDbusWps(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.credentials_received = False
+
+        def __enter__(self):
+            gobject.timeout_add(100, self.start_reg)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
+            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
+                            "Credentials")
+            self.loop.run()
+            return self
+
+        def wpsEvent(self, name, args):
+            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
+
+        def credentials(self, args):
+            logger.debug("credentials: " + str(args))
+            self.credentials_received = True
+            self.loop.quit()
+
+        def start_reg(self, *args):
+            logger.debug("start_reg")
+            bssid_ay = dbus.ByteArray(bssid.replace(':','').decode('hex'))
+            wps.Start({'Role': 'registrar', 'Type': 'pin',
+                       'Pin': '12345670', 'Bssid': bssid_ay})
+            return False
+
+        def success(self):
+            return self.credentials_received
+
+    with TestDbusWps(bus) as t:
+        if not t.success():
+            raise Exception("Failure in D-Bus operations")
+
+    dev[0].wait_connected(timeout=10)
+
+def test_dbus_scan_invalid(dev, apdev):
+    """D-Bus invalid scan method"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    tests = [ ({}, "InvalidArgs"),
+              ({'Type': 123}, "InvalidArgs"),
+              ({'Type': 'foo'}, "InvalidArgs"),
+              ({'Type': 'active', 'Foo': 'bar'}, "InvalidArgs"),
+              ({'Type': 'active', 'SSIDs': 'foo'}, "InvalidArgs"),
+              ({'Type': 'active', 'SSIDs': ['foo']}, "InvalidArgs"),
+              ({'Type': 'active',
+                'SSIDs': [ dbus.ByteArray("1"), dbus.ByteArray("2"),
+                           dbus.ByteArray("3"), dbus.ByteArray("4"),
+                           dbus.ByteArray("5"), dbus.ByteArray("6"),
+                           dbus.ByteArray("7"), dbus.ByteArray("8"),
+                           dbus.ByteArray("9"), dbus.ByteArray("10"),
+                           dbus.ByteArray("11"), dbus.ByteArray("12"),
+                           dbus.ByteArray("13"), dbus.ByteArray("14"),
+                           dbus.ByteArray("15"), dbus.ByteArray("16"),
+                           dbus.ByteArray("17") ]},
+               "InvalidArgs"),
+              ({'Type': 'active',
+                'SSIDs': [ dbus.ByteArray("1234567890abcdef1234567890abcdef1") ]},
+               "InvalidArgs"),
+              ({'Type': 'active', 'IEs': 'foo'}, "InvalidArgs"),
+              ({'Type': 'active', 'IEs': ['foo']}, "InvalidArgs"),
+              ({'Type': 'active', 'Channels': 2412 }, "InvalidArgs"),
+              ({'Type': 'active', 'Channels': [ 2412 ] }, "InvalidArgs"),
+              ({'Type': 'active',
+                'Channels': [ (dbus.Int32(2412), dbus.UInt32(20)) ] },
+               "InvalidArgs"),
+              ({'Type': 'active',
+                'Channels': [ (dbus.UInt32(2412), dbus.Int32(20)) ] },
+               "InvalidArgs"),
+              ({'Type': 'active', 'AllowRoam': "yes" }, "InvalidArgs"),
+              ({'Type': 'passive', 'IEs': [ dbus.ByteArray("\xdd\x00") ]},
+               "InvalidArgs"),
+              ({'Type': 'passive', 'SSIDs': [ dbus.ByteArray("foo") ]},
+               "InvalidArgs")]
+    for (t,err) in tests:
+        try:
+            iface.Scan(t)
+            raise Exception("Invalid Scan() arguments accepted: " + str(t))
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid Scan(%s): %s" % (str(t), str(e)))
+
+def test_dbus_scan_oom(dev, apdev):
+    """D-Bus scan method and OOM"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "wpa_scan_clone_params;wpas_dbus_handler_scan",
+                         "Scan", expected="ScanError: Scan request rejected"):
+        iface.Scan({ 'Type': 'passive',
+                     'Channels': [ (dbus.UInt32(2412), dbus.UInt32(20)) ] })
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpas_dbus_get_scan_channels;wpas_dbus_handler_scan",
+                         "Scan"):
+        iface.Scan({ 'Type': 'passive',
+                     'Channels': [ (dbus.UInt32(2412), dbus.UInt32(20)) ] })
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpas_dbus_get_scan_ies;wpas_dbus_handler_scan",
+                         "Scan"):
+        iface.Scan({ 'Type': 'active',
+                     'IEs': [ dbus.ByteArray("\xdd\x00") ],
+                     'Channels': [ (dbus.UInt32(2412), dbus.UInt32(20)) ] })
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpas_dbus_get_scan_ssids;wpas_dbus_handler_scan",
+                         "Scan"):
+        iface.Scan({ 'Type': 'active',
+                     'SSIDs': [ dbus.ByteArray("open"),
+                                dbus.ByteArray() ],
+                     'Channels': [ (dbus.UInt32(2412), dbus.UInt32(20)) ] })
+
+def test_dbus_scan(dev, apdev):
+    """D-Bus scan and related signals"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+
+    class TestDbusScan(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.scan_completed = 0
+            self.bss_added = False
+            self.fail_reason = None
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_scan)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.scanDone, WPAS_DBUS_IFACE, "ScanDone")
+            self.add_signal(self.bssAdded, WPAS_DBUS_IFACE, "BSSAdded")
+            self.add_signal(self.bssRemoved, WPAS_DBUS_IFACE, "BSSRemoved")
+            self.loop.run()
+            return self
+
+        def scanDone(self, success):
+            logger.debug("scanDone: success=%s" % success)
+            self.scan_completed += 1
+            if self.scan_completed == 1:
+                iface.Scan({'Type': 'passive',
+                            'AllowRoam': True,
+                            'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
+            elif self.scan_completed == 2:
+                iface.Scan({'Type': 'passive',
+                            'AllowRoam': False})
+            elif self.bss_added and self.scan_completed == 3:
+                self.loop.quit()
+
+        def bssAdded(self, bss, properties):
+            logger.debug("bssAdded: %s" % bss)
+            logger.debug(str(properties))
+            if 'WPS' in properties:
+                if 'Type' in properties['WPS']:
+                    self.fail_reason = "Unexpected WPS dictionary entry in non-WPS BSS"
+                    self.loop.quit()
+            self.bss_added = True
+            if self.scan_completed == 3:
+                self.loop.quit()
+
+        def bssRemoved(self, bss):
+            logger.debug("bssRemoved: %s" % bss)
+
+        def run_scan(self, *args):
+            logger.debug("run_scan")
+            iface.Scan({'Type': 'active',
+                        'SSIDs': [ dbus.ByteArray("open"),
+                                   dbus.ByteArray() ],
+                        'IEs': [ dbus.ByteArray("\xdd\x00"),
+                                 dbus.ByteArray() ],
+                        'AllowRoam': False,
+                        'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
+            return False
+
+        def success(self):
+            return self.scan_completed == 3 and self.bss_added
+
+    with TestDbusScan(bus) as t:
+        if t.fail_reason:
+            raise Exception(t.fail_reason)
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) < 1:
+        raise Exception("Scan result not in BSSs property")
+    iface.FlushBSS(0)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 0:
+        raise Exception("FlushBSS() did not remove scan results from BSSs property")
+    iface.FlushBSS(1)
+
+def test_dbus_scan_busy(dev, apdev):
+    """D-Bus scan trigger rejection when busy with previous scan"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    if "OK" not in dev[0].request("SCAN freq=2412-2462"):
+        raise Exception("Failed to start scan")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], 15)
+    if ev is None:
+        raise Exception("Scan start timed out")
+
+    try:
+        iface.Scan({'Type': 'active', 'AllowRoam': False})
+        raise Exception("Scan() accepted when busy")
+    except dbus.exceptions.DBusException, e:
+        if "ScanError: Scan request reject" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
+    if ev is None:
+        raise Exception("Scan timed out")
+
+def test_dbus_connect(dev, apdev):
+    """D-Bus AddNetwork and connect"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.network_added = False
+            self.network_selected = False
+            self.network_removed = False
+            self.state = 0
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
+            self.add_signal(self.networkRemoved, WPAS_DBUS_IFACE,
+                            "NetworkRemoved")
+            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
+                            "NetworkSelected")
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def networkAdded(self, network, properties):
+            logger.debug("networkAdded: %s" % str(network))
+            logger.debug(str(properties))
+            self.network_added = True
+
+        def networkRemoved(self, network):
+            logger.debug("networkRemoved: %s" % str(network))
+            self.network_removed = True
+
+        def networkSelected(self, network):
+            logger.debug("networkSelected: %s" % str(network))
+            self.network_selected = True
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'State' in properties and properties['State'] == "completed":
+                if self.state == 0:
+                    self.state = 1
+                    iface.Disconnect()
+                elif self.state == 2:
+                    self.state = 3
+                    iface.Disconnect()
+                elif self.state == 4:
+                    self.state = 5
+                    iface.Reattach()
+                elif self.state == 5:
+                    self.state = 6
+                    res = iface.SignalPoll()
+                    logger.debug("SignalPoll: " + str(res))
+                    if 'frequency' not in res or res['frequency'] != 2412:
+                        self.state = -1
+                        logger.info("Unexpected SignalPoll result")
+                    iface.RemoveNetwork(self.netw)
+            if 'State' in properties and properties['State'] == "disconnected":
+                if self.state == 1:
+                    self.state = 2
+                    iface.SelectNetwork(self.netw)
+                elif self.state == 3:
+                    self.state = 4
+                    iface.Reassociate()
+                elif self.state == 6:
+                    self.state = 7
+                    self.loop.quit()
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            args = dbus.Dictionary({ 'ssid': ssid,
+                                     'key_mgmt': 'WPA-PSK',
+                                     'psk': passphrase,
+                                     'scan_freq': 2412 },
+                                   signature='sv')
+            self.netw = iface.AddNetwork(args)
+            iface.SelectNetwork(self.netw)
+            return False
+
+        def success(self):
+            if not self.network_added or \
+               not self.network_removed or \
+               not self.network_selected:
+                return False
+            return self.state == 7
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_connect_psk_mem(dev, apdev):
+    """D-Bus AddNetwork and connect with memory-only PSK"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.connected = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.add_signal(self.networkRequest, WPAS_DBUS_IFACE,
+                            "NetworkRequest")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'State' in properties and properties['State'] == "completed":
+                self.connected = True
+                self.loop.quit()
+
+        def networkRequest(self, path, field, txt):
+            logger.debug("networkRequest: %s %s %s" % (path, field, txt))
+            if field == "PSK_PASSPHRASE":
+                iface.NetworkReply(path, field, '"' + passphrase + '"')
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            args = dbus.Dictionary({ 'ssid': ssid,
+                                     'key_mgmt': 'WPA-PSK',
+                                     'mem_only_psk': 1,
+                                     'scan_freq': 2412 },
+                                   signature='sv')
+            self.netw = iface.AddNetwork(args)
+            iface.SelectNetwork(self.netw)
+            return False
+
+        def success(self):
+            return self.connected
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_connect_oom(dev, apdev):
+    """D-Bus AddNetwork and connect when out-of-memory"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    if "OK" not in dev[0].request("TEST_ALLOC_FAIL 0:"):
+        raise HwsimSkip("TEST_ALLOC_FAIL not supported in the build")
+
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.network_added = False
+            self.network_selected = False
+            self.network_removed = False
+            self.state = 0
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(1500, self.timeout)
+            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
+            self.add_signal(self.networkRemoved, WPAS_DBUS_IFACE,
+                            "NetworkRemoved")
+            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
+                            "NetworkSelected")
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def networkAdded(self, network, properties):
+            logger.debug("networkAdded: %s" % str(network))
+            logger.debug(str(properties))
+            self.network_added = True
+
+        def networkRemoved(self, network):
+            logger.debug("networkRemoved: %s" % str(network))
+            self.network_removed = True
+
+        def networkSelected(self, network):
+            logger.debug("networkSelected: %s" % str(network))
+            self.network_selected = True
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'State' in properties and properties['State'] == "completed":
+                if self.state == 0:
+                    self.state = 1
+                    iface.Disconnect()
+                elif self.state == 2:
+                    self.state = 3
+                    iface.Disconnect()
+                elif self.state == 4:
+                    self.state = 5
+                    iface.Reattach()
+                elif self.state == 5:
+                    self.state = 6
+                    res = iface.SignalPoll()
+                    logger.debug("SignalPoll: " + str(res))
+                    if 'frequency' not in res or res['frequency'] != 2412:
+                        self.state = -1
+                        logger.info("Unexpected SignalPoll result")
+                    iface.RemoveNetwork(self.netw)
+            if 'State' in properties and properties['State'] == "disconnected":
+                if self.state == 1:
+                    self.state = 2
+                    iface.SelectNetwork(self.netw)
+                elif self.state == 3:
+                    self.state = 4
+                    iface.Reassociate()
+                elif self.state == 6:
+                    self.state = 7
+                    self.loop.quit()
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            args = dbus.Dictionary({ 'ssid': ssid,
+                                     'key_mgmt': 'WPA-PSK',
+                                     'psk': passphrase,
+                                     'scan_freq': 2412 },
+                                   signature='sv')
+            try:
+                self.netw = iface.AddNetwork(args)
+            except Exception, e:
+                logger.info("Exception on AddNetwork: " + str(e))
+                self.loop.quit()
+                return False
+            try:
+                iface.SelectNetwork(self.netw)
+            except Exception, e:
+                logger.info("Exception on SelectNetwork: " + str(e))
+                self.loop.quit()
+
+            return False
+
+        def success(self):
+            if not self.network_added or \
+               not self.network_removed or \
+               not self.network_selected:
+                return False
+            return self.state == 7
+
+    count = 0
+    for i in range(1, 1000):
+        for j in range(3):
+            dev[j].dump_monitor()
+        dev[0].request("TEST_ALLOC_FAIL %d:main" % i)
+        try:
+            with TestDbusConnect(bus) as t:
+                if not t.success():
+                    logger.info("Iteration %d - Expected signals not seen" % i)
+                else:
+                    logger.info("Iteration %d - success" % i)
+
+            state = dev[0].request('GET_ALLOC_FAIL')
+            logger.info("GET_ALLOC_FAIL: " + state)
+            dev[0].dump_monitor()
+            dev[0].request("TEST_ALLOC_FAIL 0:")
+            if i < 3:
+                raise Exception("Connection succeeded during out-of-memory")
+            if not state.startswith('0:'):
+                count += 1
+                if count == 5:
+                    break
+        except:
+            pass
+
+def test_dbus_while_not_connected(dev, apdev):
+    """D-Bus invalid operations while not connected"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    try:
+        iface.Disconnect()
+        raise Exception("Disconnect() accepted when not connected")
+    except dbus.exceptions.DBusException, e:
+        if "NotConnected" not in str(e):
+            raise Exception("Unexpected error message for invalid Disconnect: " + str(e))
+
+    try:
+        iface.Reattach()
+        raise Exception("Reattach() accepted when not connected")
+    except dbus.exceptions.DBusException, e:
+        if "NotConnected" not in str(e):
+            raise Exception("Unexpected error message for invalid Reattach: " + str(e))
+
+def test_dbus_connect_eap(dev, apdev):
+    """D-Bus AddNetwork and connect to EAP network"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    ssid = "ieee8021x-open"
+    params = hostapd.radius_params()
+    params["ssid"] = ssid
+    params["ieee8021x"] = "1"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.certification_received = False
+            self.eap_status = False
+            self.state = 0
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.add_signal(self.certification, WPAS_DBUS_IFACE,
+                            "Certification", byte_arrays=True)
+            self.add_signal(self.networkRequest, WPAS_DBUS_IFACE,
+                            "NetworkRequest")
+            self.add_signal(self.eap, WPAS_DBUS_IFACE, "EAP")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'State' in properties and properties['State'] == "completed":
+                if self.state == 0:
+                    self.state = 1
+                    iface.EAPLogoff()
+                    logger.info("Set dNSName constraint")
+                    net_obj = bus.get_object(WPAS_DBUS_SERVICE, self.netw)
+                    args = dbus.Dictionary({ 'altsubject_match':
+                                             self.server_dnsname },
+                                           signature='sv')
+                    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
+                                dbus_interface=dbus.PROPERTIES_IFACE)
+                elif self.state == 2:
+                    self.state = 3
+                    iface.Disconnect()
+                    logger.info("Set non-matching dNSName constraint")
+                    net_obj = bus.get_object(WPAS_DBUS_SERVICE, self.netw)
+                    args = dbus.Dictionary({ 'altsubject_match':
+                                             self.server_dnsname + "FOO" },
+                                           signature='sv')
+                    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
+                                dbus_interface=dbus.PROPERTIES_IFACE)
+            if 'State' in properties and properties['State'] == "disconnected":
+                if self.state == 1:
+                    self.state = 2
+                    iface.EAPLogon()
+                    iface.SelectNetwork(self.netw)
+                if self.state == 3:
+                    self.state = 4
+                    iface.SelectNetwork(self.netw)
+
+        def certification(self, args):
+            logger.debug("certification: %s" % str(args))
+            self.certification_received = True
+            if args['depth'] == 0:
+                # The test server certificate is supposed to have dNSName
+                if len(args['altsubject']) < 1:
+                    raise Exception("Missing dNSName")
+                dnsname = args['altsubject'][0]
+                if not dnsname.startswith("DNS:"):
+                    raise Exception("Expected dNSName not found: " + dnsname)
+                logger.info("altsubject: " + dnsname)
+                self.server_dnsname = dnsname
+
+        def eap(self, status, parameter):
+            logger.debug("EAP: status=%s parameter=%s" % (status, parameter))
+            if status == 'completion' and parameter == 'success':
+                self.eap_status = True
+            if self.state == 4 and status == 'remote certificate verification' and parameter == 'AltSubject mismatch':
+                self.state = 5
+                self.loop.quit()
+
+        def networkRequest(self, path, field, txt):
+            logger.debug("networkRequest: %s %s %s" % (path, field, txt))
+            if field == "PASSWORD":
+                iface.NetworkReply(path, field, "password")
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            args = dbus.Dictionary({ 'ssid': ssid,
+                                     'key_mgmt': 'IEEE8021X',
+                                     'eapol_flags': 0,
+                                     'eap': 'TTLS',
+                                     'anonymous_identity': 'ttls',
+                                     'identity': 'pap user',
+                                     'ca_cert': 'auth_serv/ca.pem',
+                                     'phase2': 'auth=PAP',
+                                     'scan_freq': 2412 },
+                                   signature='sv')
+            self.netw = iface.AddNetwork(args)
+            iface.SelectNetwork(self.netw)
+            return False
+
+        def success(self):
+            if not self.eap_status or not self.certification_received:
+                return False
+            return self.state == 5
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_network(dev, apdev):
+    """D-Bus AddNetwork/RemoveNetwork parameters and error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    args = dbus.Dictionary({ 'ssid': "foo",
+                             'key_mgmt': 'WPA-PSK',
+                             'psk': "12345678",
+                             'identity': dbus.ByteArray([ 1, 2 ]),
+                             'priority': dbus.Int32(0),
+                             'scan_freq': dbus.UInt32(2412) },
+                           signature='sv')
+    netw = iface.AddNetwork(args)
+    iface.RemoveNetwork(netw)
+    try:
+        iface.RemoveNetwork(netw)
+        raise Exception("Invalid RemoveNetwork() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "NetworkUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid RemoveNetwork: " + str(e))
+    try:
+        iface.SelectNetwork(netw)
+        raise Exception("Invalid SelectNetwork() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "NetworkUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid RemoveNetwork: " + str(e))
+
+    args = dbus.Dictionary({ 'ssid': "foo1", 'key_mgmt': 'NONE',
+                             'identity': "testuser", 'scan_freq': '2412' },
+                           signature='sv')
+    netw1 = iface.AddNetwork(args)
+    args = dbus.Dictionary({ 'ssid': "foo2", 'key_mgmt': 'NONE' },
+                           signature='sv')
+    netw2 = iface.AddNetwork(args)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "Networks",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 2:
+        raise Exception("Unexpected number of networks")
+
+    net_obj = bus.get_object(WPAS_DBUS_SERVICE, netw1)
+    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != False:
+        raise Exception("Added network was unexpectedly enabled by default")
+    net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.Boolean(True),
+                dbus_interface=dbus.PROPERTIES_IFACE)
+    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != True:
+        raise Exception("Set(Enabled,True) did not seem to change property value")
+    net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.Boolean(False),
+                dbus_interface=dbus.PROPERTIES_IFACE)
+    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != False:
+        raise Exception("Set(Enabled,False) did not seem to change property value")
+    try:
+        net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.UInt32(1),
+                    dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(Enabled,1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(Enabled,1): " + str(e))
+
+    args = dbus.Dictionary({ 'ssid': "foo1new" }, signature='sv')
+    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
+                dbus_interface=dbus.PROPERTIES_IFACE)
+    res = net_obj.Get(WPAS_DBUS_NETWORK, "Properties",
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+    if res['ssid'] != '"foo1new"':
+        raise Exception("Set(Properties) failed to update ssid")
+    if res['identity'] != '"testuser"':
+        raise Exception("Set(Properties) unexpectedly changed unrelated parameter")
+
+    iface.RemoveAllNetworks()
+    res = if_obj.Get(WPAS_DBUS_IFACE, "Networks",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 0:
+        raise Exception("Unexpected number of networks")
+    iface.RemoveAllNetworks()
+
+    tests = [ dbus.Dictionary({ 'psk': "1234567" }, signature='sv'),
+              dbus.Dictionary({ 'identity': dbus.ByteArray() },
+                              signature='sv'),
+              dbus.Dictionary({ 'identity': dbus.Byte(1) }, signature='sv'),
+              dbus.Dictionary({ 'identity': "" }, signature='sv') ]
+    for args in tests:
+        try:
+            iface.AddNetwork(args)
+            raise Exception("Invalid AddNetwork args accepted: " + str(args))
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid AddNetwork: " + str(e))
+
+def test_dbus_network_oom(dev, apdev):
+    """D-Bus AddNetwork/RemoveNetwork parameters and OOM error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    args = dbus.Dictionary({ 'ssid': "foo1", 'key_mgmt': 'NONE',
+                             'identity': "testuser", 'scan_freq': '2412' },
+                           signature='sv')
+    netw1 = iface.AddNetwork(args)
+    net_obj = bus.get_object(WPAS_DBUS_SERVICE, netw1)
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "wpa_config_get_all;wpas_dbus_getter_network_properties",
+                         "Get"):
+        net_obj.Get(WPAS_DBUS_NETWORK, "Properties",
+                    dbus_interface=dbus.PROPERTIES_IFACE)
+
+    iface.RemoveAllNetworks()
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "wpas_dbus_new_decompose_object_path;wpas_dbus_handler_remove_network",
+                         "RemoveNetwork", "InvalidArgs"):
+        iface.RemoveNetwork(dbus.ObjectPath("/fi/w1/wpa_supplicant1/Interfaces/1234/Networks/1234"))
+
+    with alloc_fail(dev[0], 1, "wpa_dbus_register_object_per_iface;wpas_dbus_register_network"):
+        args = dbus.Dictionary({ 'ssid': "foo2", 'key_mgmt': 'NONE' },
+                               signature='sv')
+        try:
+            netw = iface.AddNetwork(args)
+            # Currently, AddNetwork() succeeds even if os_strdup() for path
+            # fails, so remove the network if that occurs.
+            iface.RemoveNetwork(netw)
+        except dbus.exceptions.DBusException, e:
+            pass
+
+    for i in range(1, 3):
+        with alloc_fail(dev[0], i, "=wpas_dbus_register_network"):
+            try:
+                netw = iface.AddNetwork(args)
+                # Currently, AddNetwork() succeeds even if network registration
+                # fails, so remove the network if that occurs.
+                iface.RemoveNetwork(netw)
+            except dbus.exceptions.DBusException, e:
+                pass
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpa_config_add_network;wpas_dbus_handler_add_network",
+                         "AddNetwork",
+                         "UnknownError: wpa_supplicant could not add a network"):
+        args = dbus.Dictionary({ 'ssid': "foo2", 'key_mgmt': 'NONE' },
+                               signature='sv')
+        netw = iface.AddNetwork(args)
+
+    tests = [ (1,
+               'wpa_dbus_dict_get_entry;set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'ssid': dbus.ByteArray(' ') },
+                               signature='sv')),
+              (1, '=set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'ssid': 'foo' }, signature='sv')),
+              (1, '=set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'eap': 'foo' }, signature='sv')),
+              (1, '=set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'priority': dbus.UInt32(1) },
+                               signature='sv')),
+              (1, '=set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'priority': dbus.Int32(1) },
+                               signature='sv')),
+              (1, '=set_network_properties;wpas_dbus_handler_add_network',
+               dbus.Dictionary({ 'ssid': dbus.ByteArray(' ') },
+                               signature='sv')) ]
+    for (count,funcs,args) in tests:
+        with alloc_fail_dbus(dev[0], count, funcs, "AddNetwork", "InvalidArgs"):
+            netw = iface.AddNetwork(args)
+
+    if len(if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
+                      dbus_interface=dbus.PROPERTIES_IFACE)) > 0:
+        raise Exception("Unexpected network block added")
+    if len(dev[0].list_networks()) > 0:
+        raise Exception("Unexpected network block visible")
+
+def test_dbus_interface(dev, apdev):
+    """D-Bus CreateInterface/GetInterface/RemoveInterface parameters and error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
+
+    params = dbus.Dictionary({ 'Ifname': 'lo', 'Driver': 'none' },
+                             signature='sv')
+    path = wpas.CreateInterface(params)
+    logger.debug("New interface path: " + str(path))
+    path2 = wpas.GetInterface("lo")
+    if path != path2:
+        raise Exception("Interface object mismatch")
+
+    params = dbus.Dictionary({ 'Ifname': 'lo',
+                               'Driver': 'none',
+                               'ConfigFile': 'foo',
+                               'BridgeIfname': 'foo', },
+                             signature='sv')
+    try:
+        wpas.CreateInterface(params)
+        raise Exception("Invalid CreateInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InterfaceExists" not in str(e):
+            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
+
+    wpas.RemoveInterface(path)
+    try:
+        wpas.RemoveInterface(path)
+        raise Exception("Invalid RemoveInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InterfaceUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
+
+    params = dbus.Dictionary({ 'Ifname': 'lo', 'Driver': 'none',
+                               'Foo': 123 },
+                             signature='sv')
+    try:
+        wpas.CreateInterface(params)
+        raise Exception("Invalid CreateInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
+
+    params = dbus.Dictionary({ 'Driver': 'none' }, signature='sv')
+    try:
+        wpas.CreateInterface(params)
+        raise Exception("Invalid CreateInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
+
+    try:
+        wpas.GetInterface("lo")
+        raise Exception("Invalid GetInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InterfaceUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
+
+def test_dbus_interface_oom(dev, apdev):
+    """D-Bus CreateInterface/GetInterface/RemoveInterface OOM error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
+
+    with alloc_fail_dbus(dev[0], 1, "wpa_dbus_dict_get_entry;wpas_dbus_handler_create_interface", "CreateInterface", "InvalidArgs"):
+        params = dbus.Dictionary({ 'Ifname': 'lo', 'Driver': 'none' },
+                                 signature='sv')
+        wpas.CreateInterface(params)
+
+    for i in range(1, 1000):
+        dev[0].request("TEST_ALLOC_FAIL %d:wpa_supplicant_add_iface;wpas_dbus_handler_create_interface" % i)
+        params = dbus.Dictionary({ 'Ifname': 'lo', 'Driver': 'none' },
+                                 signature='sv')
+        try:
+            npath = wpas.CreateInterface(params)
+            wpas.RemoveInterface(npath)
+            logger.info("CreateInterface succeeds after %d allocation failures" % i)
+            state = dev[0].request('GET_ALLOC_FAIL')
+            logger.info("GET_ALLOC_FAIL: " + state)
+            dev[0].dump_monitor()
+            dev[0].request("TEST_ALLOC_FAIL 0:")
+            if i < 5:
+                raise Exception("CreateInterface succeeded during out-of-memory")
+            if not state.startswith('0:'):
+                break
+        except dbus.exceptions.DBusException, e:
+            pass
+
+    for arg in [ 'Driver', 'Ifname', 'ConfigFile', 'BridgeIfname' ]:
+        with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_handler_create_interface",
+                             "CreateInterface"):
+            params = dbus.Dictionary({ arg: 'foo' }, signature='sv')
+            wpas.CreateInterface(params)
+
+def test_dbus_blob(dev, apdev):
+    """D-Bus AddNetwork/RemoveNetwork parameters and error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    blob = dbus.ByteArray("\x01\x02\x03")
+    iface.AddBlob('blob1', blob)
+    try:
+        iface.AddBlob('blob1', dbus.ByteArray("\x01\x02\x04"))
+        raise Exception("Invalid AddBlob() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "BlobExists" not in str(e):
+            raise Exception("Unexpected error message for invalid AddBlob: " + str(e))
+    res = iface.GetBlob('blob1')
+    if len(res) != len(blob):
+        raise Exception("Unexpected blob data length")
+    for i in range(len(res)):
+        if res[i] != dbus.Byte(blob[i]):
+            raise Exception("Unexpected blob data")
+    res = if_obj.Get(WPAS_DBUS_IFACE, "Blobs",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if 'blob1' not in res:
+        raise Exception("Added blob missing from Blobs property")
+    iface.RemoveBlob('blob1')
+    try:
+        iface.RemoveBlob('blob1')
+        raise Exception("Invalid RemoveBlob() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "BlobUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid RemoveBlob: " + str(e))
+    try:
+        iface.GetBlob('blob1')
+        raise Exception("Invalid GetBlob() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "BlobUnknown" not in str(e):
+            raise Exception("Unexpected error message for invalid GetBlob: " + str(e))
+
+    class TestDbusBlob(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.blob_added = False
+            self.blob_removed = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_blob)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.blobAdded, WPAS_DBUS_IFACE, "BlobAdded")
+            self.add_signal(self.blobRemoved, WPAS_DBUS_IFACE, "BlobRemoved")
+            self.loop.run()
+            return self
+
+        def blobAdded(self, blobName):
+            logger.debug("blobAdded: %s" % blobName)
+            if blobName == 'blob2':
+                self.blob_added = True
+
+        def blobRemoved(self, blobName):
+            logger.debug("blobRemoved: %s" % blobName)
+            if blobName == 'blob2':
+                self.blob_removed = True
+                self.loop.quit()
+
+        def run_blob(self, *args):
+            logger.debug("run_blob")
+            iface.AddBlob('blob2', dbus.ByteArray("\x01\x02\x04"))
+            iface.RemoveBlob('blob2')
+            return False
+
+        def success(self):
+            return self.blob_added and self.blob_removed
+
+    with TestDbusBlob(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_blob_oom(dev, apdev):
+    """D-Bus AddNetwork/RemoveNetwork OOM error cases"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    for i in range(1, 4):
+        with alloc_fail_dbus(dev[0], i, "wpas_dbus_handler_add_blob",
+                             "AddBlob"):
+            iface.AddBlob('blob_no_mem', dbus.ByteArray("\x01\x02\x03\x04"))
+
+def test_dbus_autoscan(dev, apdev):
+    """D-Bus Autoscan()"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    iface.AutoScan("foo")
+    iface.AutoScan("periodic:1")
+    iface.AutoScan("")
+    dev[0].request("AUTOSCAN ")
+
+def test_dbus_autoscan_oom(dev, apdev):
+    """D-Bus Autoscan() OOM"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_handler_autoscan", "AutoScan"):
+        iface.AutoScan("foo")
+    dev[0].request("AUTOSCAN ")
+
+def test_dbus_tdls_invalid(dev, apdev):
+    """D-Bus invalid TDLS operations"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    connect_2sta_open(dev, hapd)
+    addr1 = dev[1].p2p_interface_addr()
+
+    try:
+        iface.TDLSDiscover("foo")
+        raise Exception("Invalid TDLSDiscover() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid TDLSDiscover: " + str(e))
+
+    try:
+        iface.TDLSStatus("foo")
+        raise Exception("Invalid TDLSStatus() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid TDLSStatus: " + str(e))
+
+    res = iface.TDLSStatus(addr1)
+    if res != "peer does not exist":
+        raise Exception("Unexpected TDLSStatus response")
+
+    try:
+        iface.TDLSSetup("foo")
+        raise Exception("Invalid TDLSSetup() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid TDLSSetup: " + str(e))
+
+    try:
+        iface.TDLSTeardown("foo")
+        raise Exception("Invalid TDLSTeardown() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid TDLSTeardown: " + str(e))
+
+    try:
+        iface.TDLSTeardown("00:11:22:33:44:55")
+        raise Exception("TDLSTeardown accepted for unknown peer")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: error performing TDLS teardown" not in str(e):
+            raise Exception("Unexpected error message: " + str(e))
+
+def test_dbus_tdls_oom(dev, apdev):
+    """D-Bus TDLS operations during OOM"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "wpa_tdls_add_peer", "TDLSSetup",
+                         "UnknownError: error performing TDLS setup"):
+        iface.TDLSSetup("00:11:22:33:44:55")
+
+def test_dbus_tdls(dev, apdev):
+    """D-Bus TDLS"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    connect_2sta_open(dev, hapd)
+
+    addr1 = dev[1].p2p_interface_addr()
+
+    class TestDbusTdls(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.tdls_setup = False
+            self.tdls_teardown = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_tdls)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+
+        def run_tdls(self, *args):
+            logger.debug("run_tdls")
+            iface.TDLSDiscover(addr1)
+            gobject.timeout_add(100, self.run_tdls2)
+            return False
+
+        def run_tdls2(self, *args):
+            logger.debug("run_tdls2")
+            iface.TDLSSetup(addr1)
+            gobject.timeout_add(500, self.run_tdls3)
+            return False
+
+        def run_tdls3(self, *args):
+            logger.debug("run_tdls3")
+            res = iface.TDLSStatus(addr1)
+            if res == "connected":
+                self.tdls_setup = True
+            else:
+                logger.info("Unexpected TDLSStatus: " + res)
+            iface.TDLSTeardown(addr1)
+            gobject.timeout_add(200, self.run_tdls4)
+            return False
+
+        def run_tdls4(self, *args):
+            logger.debug("run_tdls4")
+            res = iface.TDLSStatus(addr1)
+            if res == "peer does not exist":
+                self.tdls_teardown = True
+            else:
+                logger.info("Unexpected TDLSStatus: " + res)
+            self.loop.quit()
+            return False
+
+        def success(self):
+            return self.tdls_setup and self.tdls_teardown
+
+    with TestDbusTdls(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_pkcs11(dev, apdev):
+    """D-Bus SetPKCS11EngineAndModulePath()"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    try:
+        iface.SetPKCS11EngineAndModulePath("foo", "bar")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: Reinit of the EAPOL" not in str(e):
+            raise Exception("Unexpected error message for invalid SetPKCS11EngineAndModulePath: " + str(e))
+
+    try:
+        iface.SetPKCS11EngineAndModulePath("foo", "")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: Reinit of the EAPOL" not in str(e):
+            raise Exception("Unexpected error message for invalid SetPKCS11EngineAndModulePath: " + str(e))
+
+    iface.SetPKCS11EngineAndModulePath("", "bar")
+    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11EnginePath",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != "":
+        raise Exception("Unexpected PKCS11EnginePath value: " + res)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11ModulePath",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != "bar":
+        raise Exception("Unexpected PKCS11ModulePath value: " + res)
+
+    iface.SetPKCS11EngineAndModulePath("", "")
+    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11EnginePath",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != "":
+        raise Exception("Unexpected PKCS11EnginePath value: " + res)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11ModulePath",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != "":
+        raise Exception("Unexpected PKCS11ModulePath value: " + res)
+
+def test_dbus_apscan(dev, apdev):
+    """D-Bus Get/Set ApScan"""
+    try:
+        _test_dbus_apscan(dev, apdev)
+    finally:
+        dev[0].request("AP_SCAN 1")
+
+def _test_dbus_apscan(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, "ApScan",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != 1:
+        raise Exception("Unexpected initial ApScan value: %d" % res)
+
+    for i in range(3):
+        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(i),
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        res = if_obj.Get(WPAS_DBUS_IFACE, "ApScan",
+                         dbus_interface=dbus.PROPERTIES_IFACE)
+        if res != i:
+            raise Exception("Unexpected ApScan value %d (expected %d)" % (res, i))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.Int16(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(ApScan,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(ApScan,-1): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(123),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(ApScan,123) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: ap_scan must be 0, 1, or 2" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(ApScan,123): " + str(e))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(1),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+def test_dbus_fastreauth(dev, apdev):
+    """D-Bus Get/Set FastReauth"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, "FastReauth",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != True:
+        raise Exception("Unexpected initial FastReauth value: " + str(res))
+
+    for i in [ False, True ]:
+        if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Boolean(i),
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+        res = if_obj.Get(WPAS_DBUS_IFACE, "FastReauth",
+                         dbus_interface=dbus.PROPERTIES_IFACE)
+        if res != i:
+            raise Exception("Unexpected FastReauth value %d (expected %d)" % (res, i))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Int16(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(FastReauth,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(ApScan,-1): " + str(e))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Boolean(True),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+def test_dbus_bss_expire(dev, apdev):
+    """D-Bus Get/Set BSSExpireAge and BSSExpireCount"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(179),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSExpireAge",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != 179:
+        raise Exception("Unexpected BSSExpireAge value %d (expected %d)" % (res, i))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(3),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSExpireCount",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != 3:
+        raise Exception("Unexpected BSSExpireCount value %d (expected %d)" % (res, i))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.Int16(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(BSSExpireAge,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(BSSExpireAge,-1): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(9),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(BSSExpireAge,9) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: BSSExpireAge must be >= 10" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(BSSExpireAge,9): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.Int16(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(BSSExpireCount,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(BSSExpireCount,-1): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(0),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(BSSExpireCount,0) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: BSSExpireCount must be > 0" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(BSSExpireCount,0): " + str(e))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(180),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(2),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+def test_dbus_country(dev, apdev):
+    """D-Bus Get/Set Country"""
+    try:
+        _test_dbus_country(dev, apdev)
+    finally:
+        dev[0].request("SET country 00")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
+def _test_dbus_country(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    # work around issues with possible pending regdom event from the end of
+    # the previous test case
+    time.sleep(0.2)
+    dev[0].dump_monitor()
+
+    if_obj.Set(WPAS_DBUS_IFACE, "Country", "FI",
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "Country",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != "FI":
+        raise Exception("Unexpected Country value %s (expected FI)" % res)
+
+    ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"])
+    if ev is None:
+        raise Exception("regdom change event not seen")
+    if "init=USER type=COUNTRY alpha2=FI" not in ev:
+        raise Exception("Unexpected event contents: " + ev)
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "Country", dbus.Int16(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(Country,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(Country,-1): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "Country", "F",
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(Country,F) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: invalid country code" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(Country,F): " + str(e))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "Country", "00",
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+    ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"])
+    if ev is None:
+        raise Exception("regdom change event not seen")
+    if "init=CORE type=WORLD" not in ev:
+        raise Exception("Unexpected event contents: " + ev)
+
+def test_dbus_scan_interval(dev, apdev):
+    """D-Bus Get/Set ScanInterval"""
+    try:
+        _test_dbus_scan_interval(dev, apdev)
+    finally:
+        dev[0].request("SCAN_INTERVAL 5")
+
+def _test_dbus_scan_interval(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(3),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    res = if_obj.Get(WPAS_DBUS_IFACE, "ScanInterval",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if res != 3:
+        raise Exception("Unexpected ScanInterval value %d (expected %d)" % (res, i))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.UInt16(100),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(ScanInterval,100) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: wrong property type" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(ScanInterval,100): " + str(e))
+
+    try:
+        if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(-1),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(ScanInterval,-1) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: scan_interval must be >= 0" not in str(e):
+            raise Exception("Unexpected error message for invalid Set(ScanInterval,-1): " + str(e))
+
+    if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(5),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+def test_dbus_probe_req_reporting(dev, apdev):
+    """D-Bus Probe Request reporting"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    dev[0].p2p_start_go(freq=2412)
+    dev[1].p2p_find(social=True)
+
+    class TestDbusProbe(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.reported = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.probeRequest, WPAS_DBUS_IFACE, "ProbeRequest",
+                            byte_arrays=True)
+            iface.SubscribeProbeReq()
+            self.loop.run()
+            return self
+
+        def probeRequest(self, args):
+            logger.debug("probeRequest: args=%s" % str(args))
+            self.reported = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            return False
+
+        def success(self):
+            return self.reported
+
+    with TestDbusProbe(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+        iface.UnsubscribeProbeReq()
+
+    try:
+        iface.UnsubscribeProbeReq()
+        raise Exception("Invalid UnsubscribeProbeReq() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "NoSubscription" not in str(e):
+            raise Exception("Unexpected error message for invalid UnsubscribeProbeReq(): " + str(e))
+
+    with TestDbusProbe(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+        # On purpose, leave ProbeReq subscription in place to test automatic
+        # cleanup.
+
+    dev[1].p2p_stop_find()
+    dev[0].remove_group()
+
+def test_dbus_probe_req_reporting_oom(dev, apdev):
+    """D-Bus Probe Request reporting (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    # Need to make sure this process has not already subscribed to avoid false
+    # failures due to the operation succeeding due to os_strdup() not even
+    # getting called.
+    try:
+        iface.UnsubscribeProbeReq()
+        was_subscribed = True
+    except dbus.exceptions.DBusException, e:
+        was_subscribed = False
+        pass
+
+    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_handler_subscribe_preq",
+                         "SubscribeProbeReq"):
+        iface.SubscribeProbeReq()
+
+    if was_subscribed:
+        # On purpose, leave ProbeReq subscription in place to test automatic
+        # cleanup.
+        iface.SubscribeProbeReq()
+
+def test_dbus_p2p_invalid(dev, apdev):
+    """D-Bus invalid P2P operations"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    try:
+        p2p.RejectPeer(path + "/Peers/00112233445566")
+        raise Exception("Invalid RejectPeer accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: Failed to call wpas_p2p_reject" not in str(e):
+            raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
+
+    try:
+        p2p.RejectPeer("/foo")
+        raise Exception("Invalid RejectPeer accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
+
+    tests = [ {'DiscoveryType': 'foo'},
+              {'RequestedDeviceTypes': 'foo'},
+              {'RequestedDeviceTypes': ['foo']},
+              {'RequestedDeviceTypes': ['1','2','3','4','5','6','7','8','9',
+                                        '10','11','12','13','14','15','16',
+                                        '17']},
+              {'RequestedDeviceTypes': dbus.Array([], signature="s")},
+              {'RequestedDeviceTypes': dbus.Array([['foo']], signature="as")},
+              {'RequestedDeviceTypes': dbus.Array([], signature="i")},
+              {'RequestedDeviceTypes': [dbus.ByteArray('12345678'),
+                                        dbus.ByteArray('1234567')]},
+              {'Foo': dbus.Int16(1)},
+              {'Foo': dbus.UInt16(1)},
+              {'Foo': dbus.Int64(1)},
+              {'Foo': dbus.UInt64(1)},
+              {'Foo': dbus.Double(1.23)},
+              {'Foo': dbus.Signature('s')},
+              {'Foo': 'bar'}]
+    for t in tests:
+        try:
+            p2p.Find(dbus.Dictionary(t))
+            raise Exception("Invalid Find accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid Find(): " + str(e))
+
+    for p in [ "/foo",
+               "/fi/w1/wpa_supplicant1/Interfaces/1234",
+               "/fi/w1/wpa_supplicant1/Interfaces/1234/Networks/1234" ]:
+        try:
+            p2p.RemovePersistentGroup(dbus.ObjectPath(p))
+            raise Exception("Invalid RemovePersistentGroup accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid RemovePersistentGroup: " + str(e))
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        p2p.Listen(5)
+        raise Exception("Invalid Listen accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: Could not start P2P listen" not in str(e):
+            raise Exception("Unexpected error message for invalid Listen: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    test_obj = bus.get_object(WPAS_DBUS_SERVICE, path, introspect=False)
+    test_p2p = dbus.Interface(test_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    try:
+        test_p2p.Listen("foo")
+        raise Exception("Invalid Listen accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid Listen: " + str(e))
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        p2p.ExtendedListen(dbus.Dictionary({}))
+        raise Exception("Invalid ExtendedListen accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: failed to initiate a p2p_ext_listen" not in str(e):
+            raise Exception("Unexpected error message for invalid ExtendedListen: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        args = { 'duration1': 30000, 'interval1': 102400,
+                 'duration2': 20000, 'interval2': 102400 }
+        p2p.PresenceRequest(args)
+        raise Exception("Invalid PresenceRequest accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: Failed to invoke presence request" not in str(e):
+            raise Exception("Unexpected error message for invalid PresenceRequest: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    try:
+        params = dbus.Dictionary({'frequency': dbus.Int32(-1)})
+        p2p.GroupAdd(params)
+        raise Exception("Invalid GroupAdd accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid GroupAdd: " + str(e))
+
+    try:
+        params = dbus.Dictionary({'persistent_group_object':
+                                  dbus.ObjectPath(path),
+                                  'frequency': 2412})
+        p2p.GroupAdd(params)
+        raise Exception("Invalid GroupAdd accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid GroupAdd: " + str(e))
+
+    try:
+        p2p.Disconnect()
+        raise Exception("Invalid Disconnect accepted")
+    except dbus.exceptions.DBusException, e:
+        if "UnknownError: failed to disconnect" not in str(e):
+            raise Exception("Unexpected error message for invalid Disconnect: " + str(e))
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        p2p.Flush()
+        raise Exception("Invalid Flush accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Flush: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        args = { 'peer': path,
+                 'join': True,
+                 'wps_method': 'pbc',
+                 'frequency': 2412 }
+        pin = p2p.Connect(args)
+        raise Exception("Invalid Connect accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Connect: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    tests = [ { 'frequency': dbus.Int32(-1) },
+              { 'wps_method': 'pbc' },
+              { 'wps_method': 'foo' } ]
+    for args in tests:
+        try:
+            pin = p2p.Connect(args)
+            raise Exception("Invalid Connect accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid Connect: " + str(e))
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        args = { 'peer': path }
+        pin = p2p.Invite(args)
+        raise Exception("Invalid Invite accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Invite: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    try:
+        args = { 'foo': 'bar' }
+        pin = p2p.Invite(args)
+        raise Exception("Invalid Invite accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid Connect: " + str(e))
+
+    tests = [ (path, 'display', "InvalidArgs"),
+              (dbus.ObjectPath(path + "/Peers/00112233445566"),
+               'display',
+               "UnknownError: Failed to send provision discovery request"),
+              (dbus.ObjectPath(path + "/Peers/00112233445566"),
+               'keypad',
+               "UnknownError: Failed to send provision discovery request"),
+              (dbus.ObjectPath(path + "/Peers/00112233445566"),
+               'pbc',
+               "UnknownError: Failed to send provision discovery request"),
+              (dbus.ObjectPath(path + "/Peers/00112233445566"),
+               'pushbutton',
+               "UnknownError: Failed to send provision discovery request"),
+              (dbus.ObjectPath(path + "/Peers/00112233445566"),
+               'foo', "InvalidArgs") ]
+    for (p,method,err) in tests:
+        try:
+            p2p.ProvisionDiscoveryRequest(p, method)
+            raise Exception("Invalid ProvisionDiscoveryRequest accepted")
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid ProvisionDiscoveryRequest: " + str(e))
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Peers",
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Get(Peers) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Get(Peers): " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+def test_dbus_p2p_oom(dev, apdev):
+    """D-Bus P2P operations and OOM"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_string_array",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ 'bar' ] }))
+
+    with alloc_fail_dbus(dev[0], 2, "_wpa_dbus_dict_entry_get_string_array",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ 'bar' ] }))
+
+    with alloc_fail_dbus(dev[0], 10, "_wpa_dbus_dict_entry_get_string_array",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ '1','2','3','4','5','6','7','8','9' ] }))
+
+    with alloc_fail_dbus(dev[0], 1, ":=_wpa_dbus_dict_entry_get_binarray",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ dbus.ByteArray('123') ] }))
+
+    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_byte_array;_wpa_dbus_dict_entry_get_binarray",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ dbus.ByteArray('123') ] }))
+
+    with alloc_fail_dbus(dev[0], 2, "=_wpa_dbus_dict_entry_get_binarray",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123'),
+                                            dbus.ByteArray('123') ] }))
+
+    with alloc_fail_dbus(dev[0], 1, "wpabuf_alloc_ext_data;_wpa_dbus_dict_entry_get_binarray",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': [ dbus.ByteArray('123') ] }))
+
+    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_fill_value_from_variant;wpas_dbus_handler_p2p_find",
+                         "Find", "InvalidArgs"):
+        p2p.Find(dbus.Dictionary({ 'Foo': path }))
+
+    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_byte_array",
+                         "AddService", "InvalidArgs"):
+        args = { 'service_type': 'bonjour',
+                 'response': dbus.ByteArray(500*'b') }
+        p2p.AddService(args)
+
+    with alloc_fail_dbus(dev[0], 2, "_wpa_dbus_dict_entry_get_byte_array",
+                         "AddService", "InvalidArgs"):
+        p2p.AddService(args)
+
+def test_dbus_p2p_discovery(dev, apdev):
+    """D-Bus P2P discovery"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    addr0 = dev[0].p2p_dev_addr()
+
+    dev[1].request("SET sec_device_type 1-0050F204-2")
+    dev[1].request("VENDOR_ELEM_ADD 1 dd0c0050f2041049000411223344")
+    dev[1].p2p_listen()
+    addr1 = dev[1].p2p_dev_addr()
+    a1 = binascii.unhexlify(addr1.replace(':',''))
+
+    wfd_devinfo = "00001c440028"
+    dev[2].request("SET wifi_display 1")
+    dev[2].request("WFD_SUBELEM_SET 0 0006" + wfd_devinfo)
+    wfd = binascii.unhexlify('000006' + wfd_devinfo)
+    dev[2].p2p_listen()
+    addr2 = dev[2].p2p_dev_addr()
+    a2 = binascii.unhexlify(addr2.replace(':',''))
+
+    res = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+    if 'Peers' not in res:
+        raise Exception("GetAll result missing Peers")
+    if len(res['Peers']) != 0:
+        raise Exception("Unexpected peer(s) in the list")
+
+    args = {'DiscoveryType': 'social',
+            'RequestedDeviceTypes': [dbus.ByteArray('12345678')],
+            'Timeout': dbus.Int32(1) }
+    p2p.Find(dbus.Dictionary(args))
+    p2p.StopFind()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.found = False
+            self.found2 = False
+            self.lost = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.deviceLost, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceLost")
+            self.add_signal(self.provisionDiscoveryResponseEnterPin,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ProvisionDiscoveryResponseEnterPin")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            res = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Peers",
+                             dbus_interface=dbus.PROPERTIES_IFACE)
+            if len(res) < 1:
+                raise Exception("Unexpected number of peers")
+            if path not in res:
+                raise Exception("Mismatch in peer object path")
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                  dbus_interface=dbus.PROPERTIES_IFACE,
+                                  byte_arrays=True)
+            logger.debug("peer properties: " + str(res))
+
+            if res['DeviceAddress'] == a1:
+                if 'SecondaryDeviceTypes' not in res:
+                    raise Exception("Missing SecondaryDeviceTypes")
+                sec = res['SecondaryDeviceTypes']
+                if len(sec) < 1:
+                    raise Exception("Secondary device type missing")
+                if "\x00\x01\x00\x50\xF2\x04\x00\x02" not in sec:
+                    raise Exception("Secondary device type mismatch")
+
+                if 'VendorExtension' not in res:
+                    raise Exception("Missing VendorExtension")
+                vendor = res['VendorExtension']
+                if len(vendor) < 1:
+                    raise Exception("Vendor extension missing")
+                if "\x11\x22\x33\x44" not in vendor:
+                    raise Exception("Secondary device type mismatch")
+
+                self.found = True
+            elif res['DeviceAddress'] == a2:
+                if 'IEs' not in res:
+                    raise Exception("IEs missing")
+                if res['IEs'] != wfd:
+                    raise Exception("IEs mismatch")
+                self.found2 = True
+            else:
+                raise Exception("Unexpected peer device address")
+
+            if self.found and self.found2:
+                p2p.StopFind()
+                p2p.RejectPeer(path)
+                p2p.ProvisionDiscoveryRequest(path, 'display')
+
+        def deviceLost(self, path):
+            logger.debug("deviceLost: path=%s" % path)
+            self.lost = True
+            try:
+                p2p.RejectPeer(path)
+                raise Exception("Invalid RejectPeer accepted")
+            except dbus.exceptions.DBusException, e:
+                if "UnknownError: Failed to call wpas_p2p_reject" not in str(e):
+                    raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
+            self.loop.quit()
+
+        def provisionDiscoveryResponseEnterPin(self, peer_object):
+            logger.debug("provisionDiscoveryResponseEnterPin - peer=%s" % peer_object)
+            p2p.Flush()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social',
+                                      'Timeout': dbus.Int32(10)}))
+            return False
+
+        def success(self):
+            return self.found and self.lost and self.found2
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[1].request("VENDOR_ELEM_REMOVE 1 *")
+    dev[1].p2p_stop_find()
+
+    p2p.Listen(1)
+    dev[2].p2p_stop_find()
+    dev[2].request("P2P_FLUSH")
+    if not dev[2].discover_peer(addr0):
+        raise Exception("Peer not found")
+    p2p.StopFind()
+    dev[2].p2p_stop_find()
+
+    try:
+        p2p.ExtendedListen(dbus.Dictionary({'foo': 100}))
+        raise Exception("Invalid ExtendedListen accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid ExtendedListen(): " + str(e))
+
+    p2p.ExtendedListen(dbus.Dictionary({'period': 100, 'interval': 1000}))
+    p2p.ExtendedListen(dbus.Dictionary({}))
+    dev[0].global_request("P2P_EXT_LISTEN")
+
+def test_dbus_p2p_service_discovery(dev, apdev):
+    """D-Bus P2P service discovery"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+
+    bonjour_query = dbus.ByteArray(binascii.unhexlify('0b5f6166706f766572746370c00c000c01'))
+    bonjour_response = dbus.ByteArray(binascii.unhexlify('074578616d706c65c027'))
+                                   
+    args = { 'service_type': 'bonjour',
+             'query': bonjour_query,
+             'response': bonjour_response }
+    p2p.AddService(args)
+    p2p.FlushService()
+    p2p.AddService(args)
+
+    try:
+        p2p.DeleteService(args)
+        raise Exception("Invalid DeleteService() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
+
+    args = { 'service_type': 'bonjour',
+             'query': bonjour_query }
+    p2p.DeleteService(args)
+    try:
+        p2p.DeleteService(args)
+        raise Exception("Invalid DeleteService() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
+
+    args = { 'service_type': 'upnp',
+             'version': 0x10,
+             'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice' }
+    p2p.AddService(args)
+    p2p.DeleteService(args)
+    try:
+        p2p.DeleteService(args)
+        raise Exception("Invalid DeleteService() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
+
+    tests = [ { 'service_type': 'foo' },
+              { 'service_type': 'foo', 'query': bonjour_query },
+              { 'service_type': 'upnp' },
+              { 'service_type': 'upnp', 'version': 0x10 },
+              { 'service_type': 'upnp',
+                'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice' },
+              { 'version': 0x10,
+                'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice' },
+              { 'service_type': 'upnp', 'foo': 'bar' },
+              { 'service_type': 'bonjour' },
+              { 'service_type': 'bonjour', 'query': 'foo' },
+              { 'service_type': 'bonjour', 'foo': 'bar' } ]
+    for args in tests:
+        try:
+            p2p.DeleteService(args)
+            raise Exception("Invalid DeleteService() accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
+
+    tests = [ { 'service_type': 'foo' },
+              { 'service_type': 'upnp' },
+              { 'service_type': 'upnp', 'version': 0x10 },
+              { 'service_type': 'upnp',
+                'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice' },
+              { 'version': 0x10,
+                'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice' },
+              { 'service_type': 'upnp', 'foo': 'bar' },
+              { 'service_type': 'bonjour' },
+              { 'service_type': 'bonjour', 'query': 'foo' },
+              { 'service_type': 'bonjour', 'response': 'foo' },
+              { 'service_type': 'bonjour', 'query': bonjour_query },
+              { 'service_type': 'bonjour', 'response': bonjour_response },
+              { 'service_type': 'bonjour', 'query': dbus.ByteArray(500*'a') },
+              { 'service_type': 'bonjour', 'foo': 'bar' } ]
+    for args in tests:
+        try:
+            p2p.AddService(args)
+            raise Exception("Invalid AddService() accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid AddService(): " + str(e))
+
+    args = { 'tlv': dbus.ByteArray("\x02\x00\x00\x01") }
+    ref = p2p.ServiceDiscoveryRequest(args)
+    p2p.ServiceDiscoveryCancelRequest(ref)
+    try:
+        p2p.ServiceDiscoveryCancelRequest(ref)
+        raise Exception("Invalid ServiceDiscoveryCancelRequest() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid AddService(): " + str(e))
+    try:
+        p2p.ServiceDiscoveryCancelRequest(dbus.UInt64(0))
+        raise Exception("Invalid ServiceDiscoveryCancelRequest() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid AddService(): " + str(e))
+
+    args = { 'service_type': 'upnp',
+             'version': 0x10,
+             'service': 'ssdp:foo' }
+    ref = p2p.ServiceDiscoveryRequest(args)
+    p2p.ServiceDiscoveryCancelRequest(ref)
+
+    tests =  [ { 'service_type': 'foo' },
+               { 'foo': 'bar' },
+               { 'tlv': 'foo' },
+               { },
+               { 'version': 0 },
+               { 'service_type': 'upnp',
+                 'service': 'ssdp:foo' },
+               { 'service_type': 'upnp',
+                 'version': 0x10 },
+               { 'service_type': 'upnp',
+                 'version': 0x10,
+                 'service': 'ssdp:foo',
+                 'peer_object': dbus.ObjectPath(path + "/Peers") },
+               { 'service_type': 'upnp',
+                 'version': 0x10,
+                 'service': 'ssdp:foo',
+                 'peer_object': path + "/Peers" },
+               { 'service_type': 'upnp',
+                 'version': 0x10,
+                 'service': 'ssdp:foo',
+                 'peer_object': dbus.ObjectPath(path + "/Peers/00112233445566") } ]
+    for args in tests:
+        try:
+            p2p.ServiceDiscoveryRequest(args)
+            raise Exception("Invalid ServiceDiscoveryRequest accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid ServiceDiscoveryRequest(): " + str(e))
+
+    args = { 'foo': 'bar' }
+    try:
+        p2p.ServiceDiscoveryResponse(dbus.Dictionary(args, signature='sv'))
+        raise Exception("Invalid ServiceDiscoveryResponse accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e):
+            raise Exception("Unexpected error message for invalid ServiceDiscoveryResponse(): " + str(e))
+
+def test_dbus_p2p_service_discovery_query(dev, apdev):
+    """D-Bus P2P service discovery query"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    addr0 = dev[0].p2p_dev_addr()
+    dev[1].request("P2P_SERVICE_ADD bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027")
+    dev[1].p2p_listen()
+    addr1 = dev[1].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.serviceDiscoveryResponse,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ServiceDiscoveryResponse", byte_arrays=True)
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            args = { 'peer_object': path,
+                     'tlv': dbus.ByteArray("\x02\x00\x00\x01") }
+            p2p.ServiceDiscoveryRequest(args)
+
+        def serviceDiscoveryResponse(self, sd_request):
+            logger.debug("serviceDiscoveryResponse: sd_request=%s" % str(sd_request))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social',
+                                      'Timeout': dbus.Int32(10)}))
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[1].p2p_stop_find()
+
+def test_dbus_p2p_service_discovery_external(dev, apdev):
+    """D-Bus P2P service discovery with external response"""
+    try:
+        _test_dbus_p2p_service_discovery_external(dev, apdev)
+    finally:
+        dev[0].request("P2P_SERV_DISC_EXTERNAL 0")
+
+def _test_dbus_p2p_service_discovery_external(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    resp = "0300000101"
+
+    dev[1].request("P2P_FLUSH")
+    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    dev[1].p2p_find(social=True)
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.sd = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.serviceDiscoveryRequest,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ServiceDiscoveryRequest")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+
+        def serviceDiscoveryRequest(self, sd_request):
+            logger.debug("serviceDiscoveryRequest: sd_request=%s" % str(sd_request))
+            self.sd = True
+            args = { 'peer_object': sd_request['peer_object'],
+                     'frequency': sd_request['frequency'],
+                     'dialog_token': sd_request['dialog_token'],
+                     'tlvs': dbus.ByteArray(binascii.unhexlify(resp)) }
+            p2p.ServiceDiscoveryResponse(dbus.Dictionary(args, signature='sv'))
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.ServiceDiscoveryExternal(1)
+            p2p.ServiceUpdate()
+            p2p.Listen(15)
+            return False
+
+        def success(self):
+            return self.sd
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=5)
+    if ev is None:
+        raise Exception("Service discovery timed out")
+    if addr0 not in ev:
+        raise Exception("Unexpected address in SD Response: " + ev)
+    if ev.split(' ')[4] != resp:
+        raise Exception("Unexpected response data SD Response: " + ev)
+    dev[1].p2p_stop_find()
+
+    p2p.StopFind()
+    p2p.ServiceDiscoveryExternal(0)
+
+def test_dbus_p2p_autogo(dev, apdev):
+    """D-Bus P2P autonomous GO"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.first = True
+            self.waiting_end = False
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.persistentGroupAdded,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "PersistentGroupAdded")
+            self.add_signal(self.persistentGroupRemoved,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "PersistentGroupRemoved")
+            self.add_signal(self.provisionDiscoveryRequestDisplayPin,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ProvisionDiscoveryRequestDisplayPin")
+            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
+                            "StaAuthorized")
+            self.loop.run()
+            return self
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            self.group = properties['group_object']
+            role = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Role",
+                              dbus_interface=dbus.PROPERTIES_IFACE)
+            if role != "GO":
+                raise Exception("Unexpected role reported: " + role)
+            group = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Group",
+                               dbus_interface=dbus.PROPERTIES_IFACE)
+            if group != properties['group_object']:
+                raise Exception("Unexpected Group reported: " + str(group))
+            go = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PeerGO",
+                            dbus_interface=dbus.PROPERTIES_IFACE)
+            if go != '/':
+                raise Exception("Unexpected PeerGO value: " + str(go))
+            if self.first:
+                self.first = False
+                logger.info("Remove persistent group instance")
+                p2p.Disconnect()
+            else:
+                dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+                dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 join")
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            if self.waiting_end:
+                logger.info("Remove persistent group")
+                p2p.RemovePersistentGroup(self.persistent)
+            else:
+                logger.info("Re-start persistent group")
+                params = dbus.Dictionary({'persistent_group_object':
+                                          self.persistent,
+                                          'frequency': 2412})
+                p2p.GroupAdd(params)
+
+        def persistentGroupAdded(self, path, properties):
+            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
+            self.persistent = path
+
+        def persistentGroupRemoved(self, path):
+            logger.debug("persistentGroupRemoved: %s" % path)
+            self.done = True
+            self.loop.quit()
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                        dbus_interface=dbus.PROPERTIES_IFACE,
+                                        byte_arrays=True)
+            logger.debug('peer properties: ' + str(self.peer))
+
+        def provisionDiscoveryRequestDisplayPin(self, peer_object, pin):
+            logger.debug("provisionDiscoveryRequestDisplayPin - peer=%s pin=%s" % (peer_object, pin))
+            self.peer_path = peer_object
+            peer = binascii.unhexlify(peer_object.split('/')[-1])
+            addr = ""
+            for p in peer:
+                if len(addr) > 0:
+                    addr += ':'
+                addr += '%02x' % ord(p)
+
+            params = { 'Role': 'registrar',
+                       'P2PDeviceAddress': self.peer['DeviceAddress'],
+                       'Bssid': self.peer['DeviceAddress'],
+                       'Type': 'pin' }
+            try:
+                wps.Start(params)
+                raise Exception("Invalid WPS.Start() accepted")
+            except dbus.exceptions.DBusException, e:
+                if "InvalidArgs" not in str(e):
+                    raise Exception("Unexpected error message: " + str(e))
+            params = { 'Role': 'registrar',
+                       'P2PDeviceAddress': self.peer['DeviceAddress'],
+                       'Bssid': self.peer['DeviceAddress'],
+                       'Type': 'pin',
+                       'Pin': '12345670' }
+            logger.info("Authorize peer to connect to the group")
+            wps.Start(params)
+
+        def staAuthorized(self, name):
+            logger.debug("staAuthorized: " + name)
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, self.peer_path)
+            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                  dbus_interface=dbus.PROPERTIES_IFACE,
+                                  byte_arrays=True)
+            if 'Groups' not in res or len(res['Groups']) != 1:
+                raise Exception("Unexpected number of peer Groups entries")
+            if res['Groups'][0] != self.group:
+                raise Exception("Unexpected peer Groups[0] value")
+
+            g_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group)
+            res = g_obj.GetAll(WPAS_DBUS_GROUP,
+                               dbus_interface=dbus.PROPERTIES_IFACE,
+                               byte_arrays=True)
+            logger.debug("Group properties: " + str(res))
+            if 'Members' not in res or len(res['Members']) != 1:
+                raise Exception("Unexpected number of group members")
+
+            ext = dbus.ByteArray("\x11\x22\x33\x44")
+            # Earlier implementation of this interface was a bit strange. The
+            # property is defined to have aay signature and that is what the
+            # getter returned. However, the setter expected there to be a
+            # dictionary with 'WPSVendorExtensions' as the key surrounding these
+            # values.. The current implementations maintains support for that
+            # for backwards compability reasons. Verify that encoding first.
+            vals = dbus.Dictionary({ 'WPSVendorExtensions': [ ext ]},
+                                   signature='sv')
+            g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+            res = g_obj.Get(WPAS_DBUS_GROUP, 'WPSVendorExtensions',
+                               dbus_interface=dbus.PROPERTIES_IFACE,
+                               byte_arrays=True)
+            if len(res) != 1:
+                raise Exception("Unexpected number of vendor extensions")
+            if res[0] != ext:
+                raise Exception("Vendor extension value changed")
+
+            # And now verify that the more appropriate encoding is accepted as
+            # well.
+            res.append(dbus.ByteArray('\xaa\xbb\xcc\xdd\xee\xff'))
+            g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
+                      dbus_interface=dbus.PROPERTIES_IFACE)
+            res2 = g_obj.Get(WPAS_DBUS_GROUP, 'WPSVendorExtensions',
+                             dbus_interface=dbus.PROPERTIES_IFACE,
+                             byte_arrays=True)
+            if len(res) != 2:
+                raise Exception("Unexpected number of vendor extensions")
+            if res[0] != res2[0] or res[1] != res2[1]:
+                raise Exception("Vendor extension value changed")
+
+            for i in range(10):
+                res.append(dbus.ByteArray('\xaa\xbb'))
+            try:
+                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
+            except dbus.exceptions.DBusException, e:
+                if "Error.Failed" not in str(e):
+                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
+
+            vals = dbus.Dictionary({ 'Foo': [ ext ]}, signature='sv')
+            try:
+                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
+            except dbus.exceptions.DBusException, e:
+                if "InvalidArgs" not in str(e):
+                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
+
+            vals = [ "foo" ]
+            try:
+                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
+            except dbus.exceptions.DBusException, e:
+                if "Error.Failed" not in str(e):
+                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
+
+            vals = [ [ "foo" ] ]
+            try:
+                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
+            except dbus.exceptions.DBusException, e:
+                if "Error.Failed" not in str(e):
+                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
+
+            self.waiting_end = True
+            p2p.Disconnect()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            params = dbus.Dictionary({'persistent': True,
+                                      'frequency': 2412})
+            logger.info("Add a persistent group")
+            p2p.GroupAdd(params)
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[1].wait_go_ending_session()
+
+def test_dbus_p2p_autogo_pbc(dev, apdev):
+    """D-Bus P2P autonomous GO and PBC"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.first = True
+            self.waiting_end = False
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.provisionDiscoveryPBCRequest,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ProvisionDiscoveryPBCRequest")
+            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
+                            "StaAuthorized")
+            self.loop.run()
+            return self
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            self.group = properties['group_object']
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.global_request("P2P_CONNECT " + addr0 + " pbc join")
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                        dbus_interface=dbus.PROPERTIES_IFACE,
+                                        byte_arrays=True)
+            logger.debug('peer properties: ' + str(self.peer))
+
+        def provisionDiscoveryPBCRequest(self, peer_object):
+            logger.debug("provisionDiscoveryPBCRequest - peer=%s" % peer_object)
+            self.peer_path = peer_object
+            peer = binascii.unhexlify(peer_object.split('/')[-1])
+            addr = ""
+            for p in peer:
+                if len(addr) > 0:
+                    addr += ':'
+                addr += '%02x' % ord(p)
+            params = { 'Role': 'registrar',
+                       'P2PDeviceAddress': self.peer['DeviceAddress'],
+                       'Bssid': self.peer['DeviceAddress'],
+                       'Type': 'pbc' }
+            logger.info("Authorize peer to connect to the group")
+            wps.Start(params)
+
+        def staAuthorized(self, name):
+            logger.debug("staAuthorized: " + name)
+            p2p.Disconnect()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            params = dbus.Dictionary({'frequency': 2412})
+            p2p.GroupAdd(params)
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[1].wait_go_ending_session()
+    dev[1].flush_scan_cache()
+
+def test_dbus_p2p_autogo_legacy(dev, apdev):
+    """D-Bus P2P autonomous GO and legacy STA"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
+                            "StaAuthorized")
+            self.loop.run()
+            return self
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            pin = '12345670'
+            params = { 'Role': 'enrollee',
+                       'Type': 'pin',
+                       'Pin': pin }
+            wps.Start(params)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.scan_for_bss(addr0, freq=2412)
+            dev1.request("WPS_PIN " + addr0 + " " + pin)
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def staAuthorized(self, name):
+            logger.debug("staAuthorized: " + name)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.request("DISCONNECT")
+            p2p.Disconnect()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            params = dbus.Dictionary({'frequency': 2412})
+            p2p.GroupAdd(params)
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_join(dev, apdev):
+    """D-Bus P2P join an autonomous GO"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    addr1 = dev[1].p2p_dev_addr()
+    addr2 = dev[2].p2p_dev_addr()
+    dev[1].p2p_start_go(freq=2412)
+    dev[2].p2p_listen()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+            self.peer = None
+            self.go = None
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.invitationResult, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "InvitationResult")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                  dbus_interface=dbus.PROPERTIES_IFACE,
+                                  byte_arrays=True)
+            logger.debug('peer properties: ' + str(res))
+            if addr2.replace(':','') in path:
+                self.peer = path
+            elif addr1.replace(':','') in path:
+                self.go = path
+            if self.peer and self.go:
+                logger.info("Join the group")
+                p2p.StopFind()
+                args = { 'peer': self.go,
+                         'join': True,
+                         'wps_method': 'pin',
+                         'frequency': 2412 }
+                pin = p2p.Connect(args)
+
+                dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+                dev1.request("WPS_PIN any " + pin)
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            role = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Role",
+                              dbus_interface=dbus.PROPERTIES_IFACE)
+            if role != "client":
+                raise Exception("Unexpected role reported: " + role)
+            group = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Group",
+                               dbus_interface=dbus.PROPERTIES_IFACE)
+            if group != properties['group_object']:
+                raise Exception("Unexpected Group reported: " + str(group))
+            go = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PeerGO",
+                            dbus_interface=dbus.PROPERTIES_IFACE)
+            if go != self.go:
+                raise Exception("Unexpected PeerGO value: " + str(go))
+
+            g_obj = bus.get_object(WPAS_DBUS_SERVICE,
+                                   properties['group_object'])
+            res = g_obj.GetAll(WPAS_DBUS_GROUP,
+                               dbus_interface=dbus.PROPERTIES_IFACE,
+                               byte_arrays=True)
+            logger.debug("Group properties: " + str(res))
+
+            ext = dbus.ByteArray("\x11\x22\x33\x44")
+            try:
+                # Set(WPSVendorExtensions) not allowed for P2P Client
+                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
+                          dbus_interface=dbus.PROPERTIES_IFACE)
+                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
+            except dbus.exceptions.DBusException, e:
+                if "Error.Failed: Failed to set property" not in str(e):
+                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
+
+            args = { 'duration1': 30000, 'interval1': 102400,
+                     'duration2': 20000, 'interval2': 102400 }
+            p2p.PresenceRequest(args)
+
+            args = { 'peer': self.peer }
+            p2p.Invite(args)
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def invitationResult(self, result):
+            logger.debug("invitationResult: " + str(result))
+            if result['status'] != 1:
+                raise Exception("Unexpected invitation result: " + str(result))
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.remove_group()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[2].p2p_stop_find()
+
+def test_dbus_p2p_config(dev, apdev):
+    """D-Bus Get/Set P2PDeviceConfig"""
+    try:
+        _test_dbus_p2p_config(dev, apdev)
+    finally:
+        dev[0].request("P2P_SET ssid_postfix ")
+
+def _test_dbus_p2p_config(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    res = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                     dbus_interface=dbus.PROPERTIES_IFACE,
+                     byte_arrays=True)
+    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig", res,
+               dbus_interface=dbus.PROPERTIES_IFACE)
+    res2 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                      dbus_interface=dbus.PROPERTIES_IFACE,
+                      byte_arrays=True)
+
+    if len(res) != len(res2):
+        raise Exception("Different number of parameters")
+    for k in res:
+        if res[k] != res2[k]:
+            raise Exception("Parameter %s value changes" % k)
+
+    changes = { 'SsidPostfix': 'foo',
+                'VendorExtension': [ dbus.ByteArray('\x11\x22\x33\x44') ],
+                'SecondaryDeviceTypes': [ dbus.ByteArray('\x11\x22\x33\x44\x55\x66\x77\x88') ]}
+    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+               dbus.Dictionary(changes, signature='sv'),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+    res2 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                      dbus_interface=dbus.PROPERTIES_IFACE,
+                      byte_arrays=True)
+    logger.debug("P2PDeviceConfig: " + str(res2))
+    if 'VendorExtension' not in res2 or len(res2['VendorExtension']) != 1:
+        raise Exception("VendorExtension does not match")
+    if 'SecondaryDeviceTypes' not in res2 or len(res2['SecondaryDeviceTypes']) != 1:
+        raise Exception("SecondaryDeviceType does not match")
+
+    changes = { 'SsidPostfix': '',
+                'VendorExtension': dbus.Array([], signature="ay"),
+                'SecondaryDeviceTypes': dbus.Array([], signature="ay") }
+    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+               dbus.Dictionary(changes, signature='sv'),
+               dbus_interface=dbus.PROPERTIES_IFACE)
+
+    res3 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                      dbus_interface=dbus.PROPERTIES_IFACE,
+                      byte_arrays=True)
+    logger.debug("P2PDeviceConfig: " + str(res3))
+    if 'VendorExtension' in res3:
+        raise Exception("VendorExtension not removed")
+    if 'SecondaryDeviceTypes' in res3:
+        raise Exception("SecondaryDeviceType not removed")
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                   dbus_interface=dbus.PROPERTIES_IFACE,
+                   byte_arrays=True)
+        raise Exception("Invalid Get(P2PDeviceConfig) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Invite: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    try:
+        dev[0].request("P2P_SET disabled 1")
+        changes = { 'SsidPostfix': 'foo' }
+        if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                   dbus.Dictionary(changes, signature='sv'),
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+        raise Exception("Invalid Set(P2PDeviceConfig) accepted")
+    except dbus.exceptions.DBusException, e:
+        if "Error.Failed: P2P is not available for this interface" not in str(e):
+            raise Exception("Unexpected error message for invalid Invite: " + str(e))
+    finally:
+        dev[0].request("P2P_SET disabled 0")
+
+    tests = [ { 'DeviceName': 123 },
+              { 'SsidPostfix': 123 },
+              { 'Foo': 'Bar' } ]
+    for changes in tests:
+        try:
+            if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
+                       dbus.Dictionary(changes, signature='sv'),
+                       dbus_interface=dbus.PROPERTIES_IFACE)
+            raise Exception("Invalid Set(P2PDeviceConfig) accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidArgs" not in str(e):
+                raise Exception("Unexpected error message for invalid Invite: " + str(e))
+
+def test_dbus_p2p_persistent(dev, apdev):
+    """D-Bus P2P persistent group"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.persistentGroupAdded,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "PersistentGroupAdded")
+            self.loop.run()
+            return self
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            p2p.Disconnect()
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.loop.quit()
+
+        def persistentGroupAdded(self, path, properties):
+            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
+            self.persistent = path
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            params = dbus.Dictionary({'persistent': True,
+                                      'frequency': 2412})
+            logger.info("Add a persistent group")
+            p2p.GroupAdd(params)
+            return False
+
+        def success(self):
+            return True
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+        persistent = t.persistent
+
+    p_obj = bus.get_object(WPAS_DBUS_SERVICE, persistent)
+    res = p_obj.Get(WPAS_DBUS_PERSISTENT_GROUP, "Properties",
+                    dbus_interface=dbus.PROPERTIES_IFACE, byte_arrays=True)
+    logger.info("Persistent group Properties: " + str(res))
+    vals = dbus.Dictionary({ 'ssid': 'DIRECT-foo' }, signature='sv')
+    p_obj.Set(WPAS_DBUS_PERSISTENT_GROUP, "Properties", vals,
+              dbus_interface=dbus.PROPERTIES_IFACE)
+    res2 = p_obj.Get(WPAS_DBUS_PERSISTENT_GROUP, "Properties",
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != len(res2):
+        raise Exception("Different number of parameters")
+    for k in res:
+        if k != 'ssid' and res[k] != res2[k]:
+            raise Exception("Parameter %s value changes" % k)
+    if res2['ssid'] != '"DIRECT-foo"':
+        raise Exception("Unexpected ssid")
+
+    args = dbus.Dictionary({ 'ssid': 'DIRECT-testing',
+                             'psk': '1234567890' }, signature='sv')
+    group = p2p.AddPersistentGroup(args)
+
+    groups = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PersistentGroups",
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(groups) != 2:
+        raise Exception("Unexpected number of persistent groups: " + str(groups))
+
+    p2p.RemoveAllPersistentGroups()
+
+    groups = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PersistentGroups",
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(groups) != 0:
+        raise Exception("Unexpected number of persistent groups: " + str(groups))
+
+    try:
+        p2p.RemovePersistentGroup(persistent)
+        raise Exception("Invalid RemovePersistentGroup accepted")
+    except dbus.exceptions.DBusException, e:
+        if "NetworkUnknown: There is no such persistent group" not in str(e):
+            raise Exception("Unexpected error message for invalid RemovePersistentGroup: " + str(e))
+
+def test_dbus_p2p_reinvoke_persistent(dev, apdev):
+    """D-Bus P2P reinvoke persistent group"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
+
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.first = True
+            self.waiting_end = False
+            self.done = False
+            self.invited = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.persistentGroupAdded,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "PersistentGroupAdded")
+            self.add_signal(self.provisionDiscoveryRequestDisplayPin,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "ProvisionDiscoveryRequestDisplayPin")
+            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
+                            "StaAuthorized")
+            self.loop.run()
+            return self
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            if not self.invited:
+                dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+                dev1.scan_for_bss(addr0, freq=2412)
+                dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 join")
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            if self.invited:
+                self.done = True
+                self.loop.quit()
+            else:
+                dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+                dev1.request("SET persistent_reconnect 1")
+                dev1.p2p_listen()
+
+                args = { 'persistent_group_object': dbus.ObjectPath(path),
+                         'peer': self.peer_path }
+                try:
+                    pin = p2p.Invite(args)
+                    raise Exception("Invalid Invite accepted")
+                except dbus.exceptions.DBusException, e:
+                    if "InvalidArgs" not in str(e):
+                        raise Exception("Unexpected error message for invalid Invite: " + str(e))
+
+                args = { 'persistent_group_object': self.persistent,
+                         'peer': self.peer_path }
+                pin = p2p.Invite(args)
+                self.invited = True
+
+        def persistentGroupAdded(self, path, properties):
+            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
+            self.persistent = path
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
+                                        dbus_interface=dbus.PROPERTIES_IFACE,
+                                        byte_arrays=True)
+
+        def provisionDiscoveryRequestDisplayPin(self, peer_object, pin):
+            logger.debug("provisionDiscoveryRequestDisplayPin - peer=%s pin=%s" % (peer_object, pin))
+            self.peer_path = peer_object
+            peer = binascii.unhexlify(peer_object.split('/')[-1])
+            addr = ""
+            for p in peer:
+                if len(addr) > 0:
+                    addr += ':'
+                addr += '%02x' % ord(p)
+            params = { 'Role': 'registrar',
+                       'P2PDeviceAddress': self.peer['DeviceAddress'],
+                       'Bssid': self.peer['DeviceAddress'],
+                       'Type': 'pin',
+                       'Pin': '12345670' }
+            logger.info("Authorize peer to connect to the group")
+            wps.Start(params)
+
+        def staAuthorized(self, name):
+            logger.debug("staAuthorized: " + name)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.remove_group()
+            ev = dev1.wait_event(["P2P-GROUP-REMOVED"], timeout=10)
+            if ev is None:
+                raise Exception("Group removal timed out")
+            p2p.Disconnect()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            params = dbus.Dictionary({'persistent': True,
+                                      'frequency': 2412})
+            logger.info("Add a persistent group")
+            p2p.GroupAdd(params)
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_go_neg_rx(dev, apdev):
+    """D-Bus P2P GO Negotiation receive"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.goNegotiationRequest,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationRequest",
+                            byte_arrays=True)
+            self.add_signal(self.goNegotiationSuccess,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationSuccess",
+                            byte_arrays=True)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+
+        def goNegotiationRequest(self, path, dev_passwd_id):
+            logger.debug("goNegotiationRequest: path=%s dev_passwd_id=%d" % (path, dev_passwd_id))
+            if dev_passwd_id != 1:
+                raise Exception("Unexpected dev_passwd_id=%d" % dev_passwd_id)
+            args = { 'peer': path, 'wps_method': 'display', 'pin': '12345670',
+                     'go_intent': 15, 'persistent': False, 'frequency': 5175 }
+            try:
+                p2p.Connect(args)
+                raise Exception("Invalid Connect accepted")
+            except dbus.exceptions.DBusException, e:
+                if "ConnectChannelUnsupported" not in str(e):
+                    raise Exception("Unexpected error message for invalid Connect: " + str(e))
+
+            args = { 'peer': path, 'wps_method': 'display', 'pin': '12345670',
+                     'go_intent': 15, 'persistent': False }
+            p2p.Connect(args)
+
+        def goNegotiationSuccess(self, properties):
+            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            p2p.Disconnect()
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Listen(10)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            if not dev1.discover_peer(addr0):
+                raise Exception("Peer not found")
+            dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 enter")
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_go_neg_auth(dev, apdev):
+    """D-Bus P2P GO Negotiation authorized"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    addr0 = dev[0].p2p_dev_addr()
+    dev[1].p2p_listen()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+            self.peer_joined = False
+            self.peer_disconnected = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.goNegotiationSuccess,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationSuccess",
+                            byte_arrays=True)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.staDeauthorized, WPAS_DBUS_IFACE,
+                            "StaDeauthorized")
+            self.add_signal(self.peerJoined, WPAS_DBUS_GROUP,
+                            "PeerJoined")
+            self.add_signal(self.peerDisconnected, WPAS_DBUS_GROUP,
+                            "PeerDisconnected")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            args = { 'peer': path, 'wps_method': 'keypad',
+                     'go_intent': 15, 'authorize_only': True }
+            try:
+                p2p.Connect(args)
+                raise Exception("Invalid Connect accepted")
+            except dbus.exceptions.DBusException, e:
+                if "InvalidArgs" not in str(e):
+                    raise Exception("Unexpected error message for invalid Connect: " + str(e))
+
+            args = { 'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
+                     'go_intent': 15, 'authorize_only': True }
+            p2p.Connect(args)
+            p2p.Listen(10)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            if not dev1.discover_peer(addr0):
+                raise Exception("Peer not found")
+            dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=0")
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            if ev is None:
+                raise Exception("Group formation timed out")
+
+        def goNegotiationSuccess(self, properties):
+            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.remove_group()
+
+        def staDeauthorized(self, name):
+            logger.debug("staDeuthorized: " + name)
+            p2p.Disconnect()
+
+        def peerJoined(self, peer):
+            logger.debug("peerJoined: " + peer)
+            self.peer_joined = True
+
+        def peerDisconnected(self, peer):
+            logger.debug("peerDisconnected: " + peer)
+            self.peer_disconnected = True
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
+            return False
+
+        def success(self):
+            return self.done and self.peer_joined and self.peer_disconnected
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_go_neg_init(dev, apdev):
+    """D-Bus P2P GO Negotiation initiation"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    addr0 = dev[0].p2p_dev_addr()
+    dev[1].p2p_listen()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.goNegotiationSuccess,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationSuccess",
+                            byte_arrays=True)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.loop.run()
+            return self
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            args = { 'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
+                     'go_intent': 0 }
+            p2p.Connect(args)
+
+            ev = dev1.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+            if ev is None:
+                raise Exception("Timeout while waiting for GO Neg Request")
+            dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            if ev is None:
+                raise Exception("Group formation timed out")
+
+        def goNegotiationSuccess(self, properties):
+            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            p2p.Disconnect()
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            dev1.remove_group()
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_wps_failure(dev, apdev):
+    """D-Bus P2P WPS failure"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+    addr0 = dev[0].p2p_dev_addr()
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.goNegotiationRequest,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationRequest",
+                            byte_arrays=True)
+            self.add_signal(self.goNegotiationSuccess,
+                            WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GONegotiationSuccess",
+                            byte_arrays=True)
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.wpsFailed, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "WpsFailed")
+            self.loop.run()
+            return self
+
+        def goNegotiationRequest(self, path, dev_passwd_id):
+            logger.debug("goNegotiationRequest: path=%s dev_passwd_id=%d" % (path, dev_passwd_id))
+            if dev_passwd_id != 1:
+                raise Exception("Unexpected dev_passwd_id=%d" % dev_passwd_id)
+            args = { 'peer': path, 'wps_method': 'display', 'pin': '12345670',
+                     'go_intent': 15 }
+            p2p.Connect(args)
+
+        def goNegotiationSuccess(self, properties):
+            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            raise Exception("Unexpected GroupStarted")
+
+        def wpsFailed(self, name, args):
+            logger.debug("wpsFailed - name=%s args=%s" % (name, str(args)))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Listen(10)
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            if not dev1.discover_peer(addr0):
+                raise Exception("Peer not found")
+            dev1.global_request("P2P_CONNECT " + addr0 + " 87654321 enter")
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_p2p_two_groups(dev, apdev):
+    """D-Bus P2P with two concurrent groups"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    dev[0].request("SET p2p_no_group_iface 0")
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    addr2 = dev[2].p2p_dev_addr()
+    dev[1].p2p_start_go(freq=2412)
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+            self.peer = None
+            self.go = None
+            self.group1 = None
+            self.group2 = None
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, dbus.PROPERTIES_IFACE,
+                            "PropertiesChanged", byte_arrays=True)
+            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "DeviceFound")
+            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupStarted")
+            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "GroupFinished")
+            self.add_signal(self.peerJoined, WPAS_DBUS_GROUP,
+                            "PeerJoined")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, interface_name, changed_properties,
+                              invalidated_properties):
+            logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
+
+        def deviceFound(self, path):
+            logger.debug("deviceFound: path=%s" % path)
+            if addr2.replace(':','') in path:
+                self.peer = path
+            elif addr1.replace(':','') in path:
+                self.go = path
+            if self.go and not self.group1:
+                logger.info("Join the group")
+                p2p.StopFind()
+                pin = '12345670'
+                dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+                dev1.request("WPS_PIN any " + pin)
+                args = { 'peer': self.go,
+                         'join': True,
+                         'wps_method': 'pin',
+                         'pin': pin,
+                         'frequency': 2412 }
+                p2p.Connect(args)
+
+        def groupStarted(self, properties):
+            logger.debug("groupStarted: " + str(properties))
+            prop = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
+                                 dbus_interface=dbus.PROPERTIES_IFACE)
+            logger.debug("p2pdevice properties: " + str(prop))
+
+            g_obj = bus.get_object(WPAS_DBUS_SERVICE,
+                                   properties['group_object'])
+            res = g_obj.GetAll(WPAS_DBUS_GROUP,
+                               dbus_interface=dbus.PROPERTIES_IFACE,
+                               byte_arrays=True)
+            logger.debug("Group properties: " + str(res))
+
+            if not self.group1:
+                self.group1 = properties['group_object']
+                self.group1iface = properties['interface_object']
+                self.g1_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
+                                                self.group1iface)
+
+                logger.info("Start autonomous GO")
+                params = dbus.Dictionary({ 'frequency': 2412 })
+                p2p.GroupAdd(params)
+            elif not self.group2:
+                self.group2 = properties['group_object']
+                self.group2iface = properties['interface_object']
+                self.g2_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
+                                                self.group2iface)
+                self.g2_bssid = res['BSSID']
+
+            if self.group1 and self.group2:
+                logger.info("Authorize peer to join the group")
+                a2 = binascii.unhexlify(addr2.replace(':',''))
+                params = { 'Role': 'enrollee',
+                           'P2PDeviceAddress': dbus.ByteArray(a2),
+                           'Bssid': dbus.ByteArray(a2),
+                           'Type': 'pin',
+                           'Pin': '12345670' }
+                g_wps = dbus.Interface(self.g2_if_obj, WPAS_DBUS_IFACE_WPS)
+                g_wps.Start(params)
+
+                bssid = ':'.join([binascii.hexlify(l) for l in self.g2_bssid])
+                dev2 = WpaSupplicant('wlan2', '/tmp/wpas-wlan2')
+                dev2.scan_for_bss(bssid, freq=2412)
+                dev2.global_request("P2P_CONNECT " + bssid + " 12345670 join freq=2412")
+
+        def groupFinished(self, properties):
+            logger.debug("groupFinished: " + str(properties))
+
+            if self.group1 == properties['group_object']:
+                self.group1 = None
+            elif self.group2 == properties['group_object']:
+                self.group2 = None
+
+            if not self.group1 and not self.group2:
+                self.done = True
+                self.loop.quit()
+
+        def peerJoined(self, peer):
+            logger.debug("peerJoined: " + peer)
+            self.check_results()
+
+            dev2 = WpaSupplicant('wlan2', '/tmp/wpas-wlan2')
+            dev2.remove_group()
+
+            logger.info("Disconnect group2")
+            group_p2p = dbus.Interface(self.g2_if_obj,
+                                       WPAS_DBUS_IFACE_P2PDEVICE)
+            group_p2p.Disconnect()
+
+            logger.info("Disconnect group1")
+            group_p2p = dbus.Interface(self.g1_if_obj,
+                                       WPAS_DBUS_IFACE_P2PDEVICE)
+            group_p2p.Disconnect()
+
+        def check_results(self):
+            logger.info("Check results with two concurrent groups in operation")
+
+            g1_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group1)
+            res1 = g1_obj.GetAll(WPAS_DBUS_GROUP,
+                                 dbus_interface=dbus.PROPERTIES_IFACE,
+                                 byte_arrays=True)
+
+            g2_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group2)
+            res2 = g2_obj.GetAll(WPAS_DBUS_GROUP,
+                                 dbus_interface=dbus.PROPERTIES_IFACE,
+                                 byte_arrays=True)
+
+            logger.info("group1 = " + self.group1)
+            logger.debug("Group properties: " + str(res1))
+
+            logger.info("group2 = " + self.group2)
+            logger.debug("Group properties: " + str(res2))
+
+            prop = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
+                                 dbus_interface=dbus.PROPERTIES_IFACE)
+            logger.debug("p2pdevice properties: " + str(prop))
+
+            if res1['Role'] != 'client':
+                raise Exception("Group1 role reported incorrectly: " + res1['Role'])
+            if res2['Role'] != 'GO':
+                raise Exception("Group2 role reported incorrectly: " + res2['Role'])
+            if prop['Role'] != 'device':
+                raise Exception("p2pdevice role reported incorrectly: " + prop['Role'])
+
+            if len(res2['Members']) != 1:
+                   raise Exception("Unexpected Members value for group 2")
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[1].remove_group()
+
+def test_dbus_introspect(dev, apdev):
+    """D-Bus introspection"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    res = if_obj.Introspect(WPAS_DBUS_IFACE,
+                            dbus_interface=dbus.INTROSPECTABLE_IFACE)
+    logger.info("Initial Introspect: " + str(res))
+    if res is None or "Introspectable" not in res or "GroupStarted" not in res:
+        raise Exception("Unexpected initial Introspect response: " + str(res))
+
+    with alloc_fail(dev[0], 1, "wpa_dbus_introspect"):
+        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
+                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
+        logger.info("Introspect: " + str(res2))
+        if res2 is not None:
+            raise Exception("Unexpected Introspect response")
+
+    with alloc_fail(dev[0], 1, "=add_interface;wpa_dbus_introspect"):
+        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
+                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
+        logger.info("Introspect: " + str(res2))
+        if res2 is None:
+            raise Exception("No Introspect response")
+        if len(res2) >= len(res):
+            raise Exception("Unexpected Introspect response")
+
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;add_interface;wpa_dbus_introspect"):
+        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
+                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
+        logger.info("Introspect: " + str(res2))
+        if res2 is None:
+            raise Exception("No Introspect response")
+        if len(res2) >= len(res):
+            raise Exception("Unexpected Introspect response")
+
+    with alloc_fail(dev[0], 2, "=add_interface;wpa_dbus_introspect"):
+        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
+                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
+        logger.info("Introspect: " + str(res2))
+        if res2 is None:
+            raise Exception("No Introspect response")
+        if len(res2) >= len(res):
+            raise Exception("Unexpected Introspect response")
diff --git a/tests/hwsim/test_dbus_old.py b/tests/hwsim/test_dbus_old.py
new file mode 100644
index 0000000..8a76636
--- /dev/null
+++ b/tests/hwsim/test_dbus_old.py
@@ -0,0 +1,839 @@
+# wpa_supplicant D-Bus old interface tests
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger()
+
+try:
+    import gobject
+    import dbus
+    dbus_imported = True
+except ImportError:
+    dbus_imported = False
+
+import hostapd
+from utils import HwsimSkip
+from test_dbus import TestDbus, alloc_fail_dbus, start_ap
+
+WPAS_DBUS_OLD_SERVICE = "fi.epitest.hostap.WPASupplicant"
+WPAS_DBUS_OLD_PATH = "/fi/epitest/hostap/WPASupplicant"
+WPAS_DBUS_OLD_IFACE = "fi.epitest.hostap.WPASupplicant.Interface"
+WPAS_DBUS_OLD_BSSID = "fi.epitest.hostap.WPASupplicant.BSSID"
+WPAS_DBUS_OLD_NETWORK = "fi.epitest.hostap.WPASupplicant.Network"
+
+def prepare_dbus(dev):
+    if not dbus_imported:
+        raise HwsimSkip("No dbus module available")
+    try:
+        from dbus.mainloop.glib import DBusGMainLoop
+        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+        bus = dbus.SystemBus()
+        wpas_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, WPAS_DBUS_OLD_PATH)
+        wpas = dbus.Interface(wpas_obj, WPAS_DBUS_OLD_SERVICE)
+        path = wpas.getInterface(dev.ifname)
+        if_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, path)
+        return (bus,wpas_obj,path,if_obj)
+    except Exception, e:
+        raise HwsimSkip("Could not connect to D-Bus: %s" % e)
+
+class TestDbusOldWps(TestDbus):
+    def __init__(self, bus):
+        TestDbus.__init__(self, bus)
+        self.event_ok = False
+
+    def __enter__(self):
+        gobject.timeout_add(1, self.run_wps)
+        gobject.timeout_add(15000, self.timeout)
+        self.add_signal(self.wpsCred, WPAS_DBUS_OLD_IFACE, "WpsCred")
+        self.loop.run()
+        return self
+
+    def wpsCred(self, cred):
+        logger.debug("wpsCred: " + str(cred))
+        self.event_ok = True
+        self.loop.quit()
+
+    def success(self):
+        return self.event_ok
+
+def test_dbus_old(dev, apdev):
+    """The old D-Bus interface"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    res = if_obj.capabilities(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    logger.debug("capabilities(): " + str(res))
+    if 'auth_alg' not in res or "OPEN" not in res['auth_alg']:
+        raise Exception("Unexpected capabilities")
+    res2 = if_obj.capabilities(dbus.Boolean(True),
+                               dbus_interface=WPAS_DBUS_OLD_IFACE)
+    logger.debug("capabilities(strict): " + str(res2))
+    res = if_obj.state(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    logger.debug("State: " + res)
+
+    res = if_obj.scanning(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if res != 0:
+        raise Exception("Unexpected scanning: " + str(res))
+
+    if_obj.setAPScan(dbus.UInt32(1), dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    for t in [ dbus.UInt32(123), "foo" ]:
+        try:
+            if_obj.setAPScan(t, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid setAPScan() accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidOptions" not in str(e):
+                raise Exception("Unexpected error message for invalid setAPScan: " + str(e))
+
+    for p in [ path + "/Networks/12345",
+               path + "/Networks/foo" ]:
+        obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, p)
+        try:
+            obj.disable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            raise Exception("Invalid disable() accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidNetwork" not in str(e):
+                raise Exception("Unexpected error message for invalid disable: " + str(e))
+
+    for p in [ path + "/BSSIDs/foo",
+               path + "/BSSIDs/001122334455"]:
+        obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, p)
+        try:
+            obj.properties(dbus_interface=WPAS_DBUS_OLD_BSSID)
+            raise Exception("Invalid properties() accepted")
+        except dbus.exceptions.DBusException, e:
+            if "InvalidBSSID" not in str(e):
+                raise Exception("Unexpected error message for invalid properties: " + str(e))
+
+def test_dbus_old_scan(dev, apdev):
+    """The old D-Bus interface - scanning"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['wpa'] = '3'
+    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+
+    class TestDbusScan(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.scan_completed = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_scan)
+            gobject.timeout_add(7000, self.timeout)
+            self.add_signal(self.scanDone, WPAS_DBUS_OLD_IFACE,
+                            "ScanResultsAvailable")
+            self.loop.run()
+            return self
+
+        def scanDone(self):
+            logger.debug("scanDone")
+            self.scan_completed = True
+            self.loop.quit()
+
+        def run_scan(self, *args):
+            logger.debug("run_scan")
+            if not if_obj.scan(dbus_interface=WPAS_DBUS_OLD_IFACE):
+                raise Exception("Failed to trigger scan")
+            return False
+
+        def success(self):
+            return self.scan_completed
+
+    with TestDbusScan(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    res = if_obj.scanResults(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if len(res) != 2:
+        raise Exception("Unexpected number of scan results: " + str(res))
+    for i in range(2):
+        logger.debug("Scan result BSS path: " + res[i])
+        bss_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, res[i])
+        bss = bss_obj.properties(dbus_interface=WPAS_DBUS_OLD_BSSID,
+                                 byte_arrays=True)
+        logger.debug("BSS: " + str(bss))
+
+    obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, res[0])
+    try:
+        bss_obj.properties2(dbus_interface=WPAS_DBUS_OLD_BSSID)
+        raise Exception("Unknown BSSID method accepted")
+    except Exception, e:
+        logger.debug("Unknown BSSID method exception: " + str(e))
+
+    if not if_obj.flush(0, dbus_interface=WPAS_DBUS_OLD_IFACE):
+        raise Exception("Failed to issue flush(0)")
+    res = if_obj.scanResults(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if len(res) != 0:
+        raise Exception("Unexpected BSS entry after flush")
+    if not if_obj.flush(1, dbus_interface=WPAS_DBUS_OLD_IFACE):
+        raise Exception("Failed to issue flush(1)")
+    try:
+        if_obj.flush("foo", dbus_interface=WPAS_DBUS_OLD_IFACE)
+        raise Exception("Invalid flush arguments accepted")
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+            raise Exception("Unexpected error message for invalid flush: " + str(e))
+    try:
+        bss_obj.properties(dbus_interface=WPAS_DBUS_OLD_BSSID,
+                           byte_arrays=True)
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.Interface.InvalidBSSID"):
+            raise Exception("Unexpected error message for invalid BSS: " + str(e))
+
+def test_dbus_old_debug(dev, apdev):
+    """The old D-Bus interface - debug"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_OLD_SERVICE)
+
+    try:
+        wpas.setDebugParams(123)
+        raise Exception("Invalid setDebugParams accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidOptions" not in str(e):
+            raise Exception("Unexpected error message for invalid setDebugParam: " + str(e))
+
+    try:
+        wpas.setDebugParams(123, True, True)
+        raise Exception("Invalid setDebugParams accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidOptions" not in str(e):
+            raise Exception("Unexpected error message for invalid setDebugParam: " + str(e))
+
+    wpas.setDebugParams(1, True, True)
+    dev[0].request("LOG_LEVEL MSGDUMP")
+
+def test_dbus_old_smartcard(dev, apdev):
+    """The old D-Bus interface - smartcard"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    params = dbus.Dictionary(signature='sv')
+    if_obj.setSmartcardModules(params, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    params = dbus.Dictionary({ 'opensc_engine_path': "foobar1",
+                               'pkcs11_engine_path': "foobar2",
+                               'pkcs11_module_path': "foobar3",
+                               'foo': 'bar' },
+                             signature='sv')
+    params2 = dbus.Dictionary({ 'pkcs11_engine_path': "foobar2",
+                                'foo': 'bar' },
+                              signature='sv')
+    params3 = dbus.Dictionary({ 'pkcs11_module_path': "foobar3",
+                                'foo2': 'bar' },
+                              signature='sv')
+    params4 = dbus.Dictionary({ 'opensc_engine_path': "foobar4",
+                                'foo3': 'bar' },
+                              signature='sv')
+    tests = [ 1, params, params2, params3, params4 ]
+    for t in tests:
+        try:
+            if_obj.setSmartcardModules(t, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid setSmartcardModules accepted: " + str(t))
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+                raise Exception("Unexpected error message for invalid setSmartcardModules(%s): %s" % (str(t), str(e)))
+
+def test_dbus_old_smartcard_oom(dev, apdev):
+    """The old D-Bus interface - smartcard (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    for arg in [ 'opensc_engine_path', 'pkcs11_engine_path', 'pkcs11_module_path' ]:
+        with alloc_fail_dbus(dev[0], 1,
+                             "=wpas_dbus_iface_set_smartcard_modules",
+                             "setSmartcardModules",
+                             "InvalidOptions"):
+            params = dbus.Dictionary({ arg : "foo", }, signature='sv')
+            if_obj.setSmartcardModules(params,
+                                       dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "=_wpa_dbus_dict_fill_value_from_variant;wpas_dbus_iface_set_smartcard_modules",
+                         "setSmartcardModules", "InvalidOptions"):
+        params = dbus.Dictionary({ arg : "foo", }, signature='sv')
+        if_obj.setSmartcardModules(params, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+def test_dbus_old_interface(dev, apdev):
+    """The old D-Bus interface - interface get/add/remove"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_OLD_SERVICE)
+
+    tests = [ (123, "InvalidOptions"),
+              ("foo", "InvalidInterface") ]
+    for (ifname,err) in tests:
+        try:
+            wpas.getInterface(ifname)
+            raise Exception("Invalid getInterface accepted")
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid getInterface: " + str(e))
+
+    params = dbus.Dictionary({ 'driver': 'none' }, signature='sv')
+    wpas.addInterface("lo", params)
+    path = wpas.getInterface("lo")
+    logger.debug("New interface path: " + str(path))
+    wpas.removeInterface(path)
+    try:
+        wpas.removeInterface(path)
+        raise Exception("Invalid removeInterface() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidInterface" not in str(e):
+            raise Exception("Unexpected error message for invalid removeInterface: " + str(e))
+
+    params1 = dbus.Dictionary({ 'driver': 'foo',
+                                'driver-params': 'foo',
+                                'config-file': 'foo',
+                                'bridge-ifname': 'foo' },
+                              signature='sv')
+    params2 = dbus.Dictionary({ 'foo': 'bar' }, signature='sv')
+    tests = [ (123, None, "InvalidOptions"),
+              ("", None, "InvalidOptions"),
+              ("foo", None, "AddError"),
+              ("foo", params1, "AddError"),
+              ("foo", params2, "InvalidOptions"),
+              ("foo", 1234, "InvalidOptions"),
+              (dev[0].ifname, None, "ExistsError" ) ]
+    for (ifname,params,err) in tests:
+        try:
+            if params is None:
+                wpas.addInterface(ifname)
+            else:
+                wpas.addInterface(ifname, params)
+            raise Exception("Invalid addInterface accepted: " + str(params))
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid addInterface(%s): %s" % (str(params), str(e)))
+
+    try:
+        wpas.removeInterface(123)
+        raise Exception("Invalid removeInterface accepted")
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+            raise Exception("Unexpected error message for invalid removeInterface: " + str(e))
+
+def test_dbus_old_interface_oom(dev, apdev):
+    """The old D-Bus interface - interface get/add/remove (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_OLD_SERVICE)
+
+    with alloc_fail_dbus(dev[0], 1, "=_wpa_dbus_dict_fill_value_from_variant;wpas_dbus_global_add_interface",
+                         "addInterface", "InvalidOptions"):
+        params = dbus.Dictionary({ 'driver': 'none' }, signature='sv')
+        wpas.addInterface("lo", params)
+
+    for arg in [ "driver", "driver-params", "config-file", "bridge-ifname" ]:
+        with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_global_add_interface",
+                             "addInterface", "InvalidOptions"):
+            params = dbus.Dictionary({ arg: 'foo' }, signature='sv')
+            wpas.addInterface("lo", params)
+
+def test_dbus_old_blob(dev, apdev):
+    """The old D-Bus interface - blob operations"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    param1 = dbus.Dictionary({ 'blob3': 123 }, signature='sv')
+    param2 = dbus.Dictionary({ 'blob3': "foo" })
+    param3 = dbus.Dictionary({ '': dbus.ByteArray([ 1, 2 ]) },
+                             signature='sv')
+    tests = [ (1, "InvalidOptions"),
+              (param1, "InvalidOptions"),
+              (param2, "InvalidOptions"),
+              (param3, "InvalidOptions") ]
+    for (arg,err) in tests:
+        try:
+            if_obj.setBlobs(arg, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid setBlobs() accepted: " + str(arg))
+        except dbus.exceptions.DBusException, e:
+            logger.debug("setBlobs(%s): %s" % (str(arg), str(e)))
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid setBlobs: " + str(e))
+
+    tests = [ (["foo"], "RemoveError: Error removing blob"),
+              ([""], "RemoveError: Invalid blob name"),
+              ([1], "InvalidOptions"),
+              ("foo", "InvalidOptions") ]
+    for (arg,err) in tests:
+        try:
+            if_obj.removeBlobs(arg, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid removeBlobs() accepted: " + str(arg))
+        except dbus.exceptions.DBusException, e:
+            logger.debug("removeBlobs(%s): %s" % (str(arg), str(e)))
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid removeBlobs: " + str(e))
+
+    blobs = dbus.Dictionary({ 'blob1': dbus.ByteArray([ 1, 2, 3 ]),
+                              'blob2': dbus.ByteArray([ 1, 2 ]) },
+                            signature='sv')
+    if_obj.setBlobs(blobs, dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if_obj.removeBlobs(['blob1', 'blob2'], dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+def test_dbus_old_blob_oom(dev, apdev):
+    """The old D-Bus interface - blob operations (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    blobs = dbus.Dictionary({ 'blob1': dbus.ByteArray([ 1, 2, 3 ]),
+                              'blob2': dbus.ByteArray([ 1, 2 ]) },
+                            signature='sv')
+
+    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_iface_set_blobs", "setBlobs",
+                         "AddError: Not enough memory to add blob"):
+        if_obj.setBlobs(blobs, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 2, "=wpas_dbus_iface_set_blobs", "setBlobs",
+                         "AddError: Not enough memory to add blob data"):
+        if_obj.setBlobs(blobs, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 3, "=wpas_dbus_iface_set_blobs", "setBlobs",
+                         "AddError: Error adding blob"):
+        if_obj.setBlobs(blobs, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_decompose_object_path;wpas_iface_message_handler",
+                         "setBlobs",
+                         "InvalidInterface: wpa_supplicant knows nothing about this interface"):
+        if_obj.setBlobs(blobs, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+def test_dbus_old_connect(dev, apdev):
+    """The old D-Bus interface - add a network and connect"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    for p in [ "/no/where/to/be/found",
+               path + "/Networks/12345",
+               path + "/Networks/foo",
+               "/fi/epitest/hostap/WPASupplicant/Interfaces",
+               "/fi/epitest/hostap/WPASupplicant/Interfaces/12345/Networks/0" ]:
+        obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, p)
+        try:
+            if_obj.removeNetwork(obj, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid removeNetwork accepted: " + p)
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.epitest.hostap.WPASupplicant.Interface.InvalidNetwork"):
+                raise Exception("Unexpected error message for invalid removeNetwork: " + str(e))
+
+    try:
+        if_obj.removeNetwork("foo", dbus_interface=WPAS_DBUS_OLD_IFACE)
+        raise Exception("Invalid removeNetwork accepted")
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+            raise Exception("Unexpected error message for invalid removeNetwork: " + str(e))
+
+    try:
+        if_obj.removeNetwork(path, dbus_interface=WPAS_DBUS_OLD_IFACE)
+        raise Exception("Invalid removeNetwork accepted")
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.Interface.InvalidNetwork"):
+            raise Exception("Unexpected error message for invalid removeNetwork: " + str(e))
+
+    tests = [ (path, "InvalidNetwork"),
+              (bus.get_object(WPAS_DBUS_OLD_SERVICE, "/no/where"),
+               "InvalidInterface"),
+              (bus.get_object(WPAS_DBUS_OLD_SERVICE, path + "/Networks/1234"),
+               "InvalidNetwork"),
+              (bus.get_object(WPAS_DBUS_OLD_SERVICE, path + "/Networks/foo"),
+               "InvalidNetwork"),
+              (1, "InvalidOptions") ]
+    for t,err in tests:
+        try:
+            if_obj.selectNetwork(t, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid selectNetwork accepted: " + str(t))
+        except dbus.exceptions.DBusException, e:
+            if err not in str(e):
+                raise Exception("Unexpected error message for invalid selectNetwork(%s): %s" % (str(t), str(e)))
+
+    npath = if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if not npath.startswith(WPAS_DBUS_OLD_PATH):
+        raise Exception("Unexpected addNetwork result: " + path)
+    netw_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, npath)
+    tests = [ 123,
+              dbus.Dictionary({ 'foo': 'bar' }, signature='sv') ]
+    for t in tests:
+        try:
+            netw_obj.set(t, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            raise Exception("Invalid set() accepted: " + str(t))
+        except dbus.exceptions.DBusException, e:
+            if "InvalidOptions" not in str(e):
+                raise Exception("Unexpected error message for invalid set: " + str(e))
+    params = dbus.Dictionary({ 'ssid': ssid,
+                               'key_mgmt': 'WPA-PSK',
+                               'psk': passphrase,
+                               'identity': dbus.ByteArray([ 1, 2 ]),
+                               'priority': dbus.Int32(0),
+                               'scan_freq': dbus.UInt32(2412) },
+                             signature='sv')
+    netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+    if_obj.removeNetwork(npath, dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.state = 0
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.scanDone, WPAS_DBUS_OLD_IFACE,
+                            "ScanResultsAvailable")
+            self.add_signal(self.stateChange, WPAS_DBUS_OLD_IFACE,
+                            "StateChange")
+            self.loop.run()
+            return self
+
+        def scanDone(self):
+            logger.debug("scanDone")
+
+        def stateChange(self, new, old):
+            logger.debug("stateChange(%d): %s --> %s" % (self.state, old, new))
+            if new == "COMPLETED":
+                if self.state == 0:
+                    self.state = 1
+                    self.netw_obj.disable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+                elif self.state == 2:
+                    self.state = 3
+                    if_obj.disconnect(dbus_interface=WPAS_DBUS_OLD_IFACE)
+                elif self.state == 4:
+                    self.state = 5
+                    if_obj.disconnect(dbus_interface=WPAS_DBUS_OLD_IFACE)
+                elif self.state == 6:
+                    self.state = 7
+                    if_obj.removeNetwork(self.path,
+                                         dbus_interface=WPAS_DBUS_OLD_IFACE)
+                    try:
+                        if_obj.removeNetwork(self.path,
+                                             dbus_interface=WPAS_DBUS_OLD_IFACE)
+                        raise Exception("Invalid removeNetwork accepted")
+                    except dbus.exceptions.DBusException, e:
+                        if not str(e).startswith("fi.epitest.hostap.WPASupplicant.Interface.InvalidNetwork"):
+                            raise Exception("Unexpected error message for invalid wpsPbc: " + str(e))
+
+                    self.loop.quit()
+            elif new == "DISCONNECTED":
+                if self.state == 1:
+                    self.state = 2
+                    self.netw_obj.enable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+                elif self.state == 3:
+                    self.state = 4
+                    if_obj.selectNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+                elif self.state == 5:
+                    self.state = 6
+                    if_obj.selectNetwork(self.path,
+                                         dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            path = if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+            netw_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, path)
+            netw_obj.disable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            params = dbus.Dictionary({ 'ssid': ssid,
+                                       'key_mgmt': 'WPA-PSK',
+                                       'psk': passphrase,
+                                       'scan_freq': 2412 },
+                                     signature='sv')
+            netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            netw_obj.enable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            self.path = path
+            self.netw_obj = netw_obj
+            return False
+
+        def success(self):
+            return self.state == 7
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    if len(dev[0].list_networks()) != 0:
+        raise Exception("Unexpected network")
+
+def test_dbus_old_connect_eap(dev, apdev):
+    """The old D-Bus interface - add an EAP network and connect"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    ssid = "test-wpa2-eap"
+    params = hostapd.wpa2_eap_params(ssid=ssid)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.connected = False
+            self.certification_received = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.stateChange, WPAS_DBUS_OLD_IFACE,
+                            "StateChange")
+            self.add_signal(self.certification, WPAS_DBUS_OLD_IFACE,
+                            "Certification")
+            self.loop.run()
+            return self
+
+        def stateChange(self, new, old):
+            logger.debug("stateChange: %s --> %s" % (old, new))
+            if new == "COMPLETED":
+                self.connected = True
+                self.loop.quit()
+
+        def certification(self, depth, subject, hash, cert_hex):
+            logger.debug("certification: depth={} subject={} hash={} cert_hex={}".format(depth, subject, hash, cert_hex))
+            self.certification_received = True
+
+        def run_connect(self, *args):
+            logger.debug("run_connect")
+            path = if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+            netw_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, path)
+            params = dbus.Dictionary({ 'ssid': ssid,
+                                       'key_mgmt': 'WPA-EAP',
+                                       'eap': 'TTLS',
+                                       'anonymous_identity': 'ttls',
+                                       'identity': 'pap user',
+                                       'ca_cert': 'auth_serv/ca.pem',
+                                       'phase2': 'auth=PAP',
+                                       'password': 'password',
+                                       'scan_freq': 2412 },
+                                     signature='sv')
+            netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            netw_obj.enable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+            self.path = path
+            self.netw_obj = netw_obj
+            return False
+
+        def success(self):
+            return self.connected and self.certification_received
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_old_network_set(dev, apdev):
+    """The old D-Bus interface and network set method"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    path = if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    netw_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, path)
+    netw_obj.disable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+
+    params = dbus.Dictionary({ 'priority': dbus.UInt64(1) }, signature='sv')
+    try:
+        netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+        raise Exception("set succeeded with unexpected type")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidOptions" not in str(e):
+            raise Exception("Unexpected error message for unexpected type: " + str(e))
+
+def test_dbus_old_wps_pbc(dev, apdev):
+    """The old D-Bus interface and WPS/PBC"""
+    try:
+        _test_dbus_old_wps_pbc(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_old_wps_pbc(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    hapd = start_ap(apdev[0])
+    hapd.request("WPS_PBC")
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    for arg in [ 123, "123" ]:
+        try:
+            if_obj.wpsPbc(arg, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid wpsPbc arguments accepted: " + str(arg))
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+                raise Exception("Unexpected error message for invalid wpsPbc: " + str(e))
+
+    class TestDbusWps(TestDbusOldWps):
+        def __init__(self, bus, pbc_param):
+            TestDbusOldWps.__init__(self, bus)
+            self.pbc_param = pbc_param
+
+        def run_wps(self, *args):
+            logger.debug("run_wps: pbc_param=" + self.pbc_param)
+            if_obj.wpsPbc(self.pbc_param, dbus_interface=WPAS_DBUS_OLD_IFACE)
+            return False
+
+    with TestDbusWps(bus, "any") as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    res = if_obj.scanResults(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    if len(res) != 1:
+        raise Exception("Unexpected number of scan results: " + str(res))
+    for i in range(1):
+        logger.debug("Scan result BSS path: " + res[i])
+        bss_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, res[i])
+        bss = bss_obj.properties(dbus_interface=WPAS_DBUS_OLD_BSSID,
+                                 byte_arrays=True)
+        logger.debug("BSS: " + str(bss))
+
+    dev[0].wait_connected(timeout=10)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    dev[0].request("FLUSH")
+
+    hapd.request("WPS_PBC")
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    with TestDbusWps(bus, bssid) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[0].wait_connected(timeout=10)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+
+    hapd.disable()
+    dev[0].flush_scan_cache()
+
+def test_dbus_old_wps_pin(dev, apdev):
+    """The old D-Bus interface and WPS/PIN"""
+    try:
+        _test_dbus_old_wps_pin(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_old_wps_pin(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    hapd = start_ap(apdev[0])
+    hapd.request("WPS_PIN any 12345670")
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    for arg in [ (123, "12345670"),
+                 ("123", "12345670") ]:
+        try:
+            if_obj.wpsPin(arg[0], arg[1], dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid wpsPin arguments accepted: " + str(arg))
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+                raise Exception("Unexpected error message for invalid wpsPbc: " + str(e))
+
+    class TestDbusWps(TestDbusOldWps):
+        def __init__(self, bus, bssid, pin):
+            TestDbusOldWps.__init__(self, bus)
+            self.bssid = bssid
+            self.pin = pin
+
+        def run_wps(self, *args):
+            logger.debug("run_wps %s %s" % (self.bssid, self.pin))
+            pin = if_obj.wpsPin(self.bssid, self.pin,
+                                dbus_interface=WPAS_DBUS_OLD_IFACE)
+            if len(self.pin) == 0:
+                h = hostapd.Hostapd(apdev[0]['ifname'])
+                h.request("WPS_PIN any " + pin)
+            return False
+
+    with TestDbusWps(bus, bssid, "12345670") as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[0].wait_connected(timeout=10)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    dev[0].request("FLUSH")
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    with TestDbusWps(bus, "any", "") as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+def test_dbus_old_wps_reg(dev, apdev):
+    """The old D-Bus interface and WPS/Registar"""
+    try:
+        _test_dbus_old_wps_reg(dev, apdev)
+    finally:
+        dev[0].request("SET wps_cred_processing 0")
+
+def _test_dbus_old_wps_reg(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET wps_cred_processing 2")
+
+    for arg in [ (123, "12345670"),
+                 ("123", "12345670") ]:
+        try:
+            if_obj.wpsReg(arg[0], arg[1], dbus_interface=WPAS_DBUS_OLD_IFACE)
+            raise Exception("Invalid wpsReg arguments accepted: " + str(arg))
+        except dbus.exceptions.DBusException, e:
+            if not str(e).startswith("fi.epitest.hostap.WPASupplicant.InvalidOptions"):
+                raise Exception("Unexpected error message for invalid wpsPbc: " + str(e))
+
+    class TestDbusWps(TestDbusOldWps):
+        def run_wps(self, *args):
+            logger.debug("run_wps")
+            if_obj.wpsReg(bssid, "12345670", dbus_interface=WPAS_DBUS_OLD_IFACE)
+            return False
+
+    with TestDbusWps(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[0].wait_connected(timeout=10)
+
+def test_dbus_old_wps_oom(dev, apdev):
+    """The old D-Bus interface and WPS (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    bssid = apdev[0]['bssid']
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpa_config_add_network;wpas_dbus_iface_wps_pbc",
+                         "wpsPbc",
+                         "WpsPbcError: Could not start PBC negotiation"):
+        if_obj.wpsPbc("any", dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpa_config_add_network;wpas_dbus_iface_wps_pin",
+                         "wpsPin", "WpsPinError: Could not init PIN"):
+        if_obj.wpsPin("any", "", dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpa_config_add_network;wpas_dbus_iface_wps_reg",
+                         "wpsReg",
+                         "WpsRegError: Could not request credentials"):
+        if_obj.wpsReg(bssid, "12345670", dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+def test_dbus_old_network_set_oom(dev, apdev):
+    """The old D-Bus interface and network set method (OOM)"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "=wpa_config_add_network;wpas_dbus_iface_add_network",
+                         "addNetwork",
+                         "AddNetworkError: wpa_supplicant could not add"):
+        if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+
+    path = if_obj.addNetwork(dbus_interface=WPAS_DBUS_OLD_IFACE)
+    netw_obj = bus.get_object(WPAS_DBUS_OLD_SERVICE, path)
+    netw_obj.disable(dbus_interface=WPAS_DBUS_OLD_NETWORK)
+
+    with alloc_fail_dbus(dev[0], 1,
+                         "_wpa_dbus_dict_fill_value_from_variant;wpas_dbus_iface_set_network",
+                         "set", "InvalidOptions"):
+        params = dbus.Dictionary({ 'ssid': "foo" }, signature='sv')
+        netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
+
+    tests = [ { 'identity': dbus.ByteArray([ 1, 2 ]) },
+              { 'scan_freq': dbus.UInt32(2412) },
+              { 'priority': dbus.Int32(0) },
+              { 'identity': "user" },
+              { 'eap': "TLS" }]
+    for arg in tests:
+        with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_iface_set_network",
+                             "set", "InvalidOptions"):
+            params = dbus.Dictionary(arg, signature='sv')
+            netw_obj.set(params, dbus_interface=WPAS_DBUS_OLD_NETWORK)
diff --git a/tests/hwsim/test_dfs.py b/tests/hwsim/test_dfs.py
index 08ded31..592736e 100644
--- a/tests/hwsim/test_dfs.py
+++ b/tests/hwsim/test_dfs.py
@@ -12,6 +12,7 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
 
 def wait_dfs_event(hapd, event, timeout):
     dfs_events = [ "DFS-RADAR-DETECTED", "DFS-NEW-CHANNEL",
@@ -68,7 +69,9 @@
     if state != "DFS":
         if allow_failure:
             logger.info("Interface state not DFS: " + state)
-            return None
+            if not os.path.exists("dfs"):
+                raise HwsimSkip("Assume DFS testing not supported")
+            raise Exception("Failed to start DFS AP")
         raise Exception("Unexpected interface state: " + state)
 
     return hapd
@@ -83,11 +86,8 @@
 def test_dfs(dev, apdev):
     """DFS CAC functionality on clear channel"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
 
         ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
         if "success=1" not in ev:
@@ -133,18 +133,15 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_dfs_radar(dev, apdev):
     """DFS CAC functionality with radar detected"""
     try:
+        hapd = None
         hapd2 = None
         hapd = start_dfs_ap(apdev[0], allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
@@ -216,7 +213,7 @@
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_dfs_radar_on_non_dfs_channel(dev, apdev):
@@ -230,11 +227,8 @@
 def test_dfs_radar_chanlist(dev, apdev):
     """DFS chanlist when radar is detected"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], chanlist="40 44", allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
@@ -261,18 +255,15 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_dfs_radar_chanlist_vht80(dev, apdev):
     """DFS chanlist when radar is detected and VHT80 configured"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], chanlist="36", ht40=True, vht80=True,
                             allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
@@ -302,18 +293,15 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_dfs_radar_chanlist_vht20(dev, apdev):
     """DFS chanlist when radar is detected and VHT40 configured"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], chanlist="36", vht20=True,
                             allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
@@ -340,18 +328,15 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_dfs_radar_no_ht(dev, apdev):
     """DFS chanlist when radar is detected and no HT configured"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], chanlist="36", ht=False,
                             allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
@@ -384,12 +369,9 @@
 def test_dfs_radar_ht40minus(dev, apdev):
     """DFS chanlist when radar is detected and HT40- configured"""
     try:
+        hapd = None
         hapd = start_dfs_ap(apdev[0], chanlist="36", ht40minus=True,
                             allow_failure=True)
-        if hapd is None:
-            if not os.path.exists("dfs"):
-                return "skip"
-            raise Exception("Failed to start DFS AP")
         time.sleep(1)
 
         dfs_simulate_radar(hapd)
diff --git a/tests/hwsim/test_eap_proto.py b/tests/hwsim/test_eap_proto.py
index 9486545..6c5d8e1 100644
--- a/tests/hwsim/test_eap_proto.py
+++ b/tests/hwsim/test_eap_proto.py
@@ -13,6 +13,7 @@
 import time
 
 import hostapd
+from utils import HwsimSkip
 
 EAP_CODE_REQUEST = 1
 EAP_CODE_RESPONSE = 2
@@ -53,7 +54,7 @@
         import pyrad.packet
         import pyrad.dictionary
     except ImportError:
-        return None
+        raise HwsimSkip("No pyrad modules available")
 
     class TestServer(pyrad.server.Server):
         def _HandleAuthPacket(self, pkt):
@@ -260,8 +261,6 @@
         return None
 
     srv = start_radius_server(eap_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -528,8 +527,6 @@
         return sake_challenge(ctx)
 
     srv = start_radius_server(sake_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -704,8 +701,6 @@
         return None
 
     srv = start_radius_server(leap_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -766,8 +761,6 @@
         return None
 
     srv = start_radius_server(md5_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -819,8 +812,6 @@
         return None
 
     srv = start_radius_server(otp_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -1274,8 +1265,6 @@
         return None
 
     srv = start_radius_server(gpsk_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -1582,8 +1571,6 @@
         return None
 
     srv = start_radius_server(eke_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -1904,8 +1891,6 @@
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
     srv = start_radius_server(pax_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -2043,8 +2028,6 @@
         return None
 
     srv = start_radius_server(psk_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -2786,8 +2769,6 @@
         return None
 
     srv = start_radius_server(aka_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -3133,8 +3114,6 @@
         return None
 
     srv = start_radius_server(aka_prime_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -3539,8 +3518,6 @@
         return None
 
     srv = start_radius_server(sim_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
@@ -4002,8 +3979,6 @@
         return None
 
     srv = start_radius_server(ikev2_handler)
-    if srv is None:
-        return "skip"
 
     try:
         hapd = start_ap(apdev[0]['ifname'])
diff --git a/tests/hwsim/test_erp.py b/tests/hwsim/test_erp.py
index 5073622..0886444 100644
--- a/tests/hwsim/test_erp.py
+++ b/tests/hwsim/test_erp.py
@@ -1,14 +1,24 @@
 # EAP Re-authentication Protocol (ERP) tests
-# Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import binascii
 import logging
 logger = logging.getLogger()
+import os
+import time
 
 import hostapd
+from utils import HwsimSkip
 from test_ap_eap import int_eap_server_params
+from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
+
+def check_erp_capa(dev):
+    capab = dev.get_capability("erp")
+    if not capab or 'ERP' not in capab:
+        raise HwsimSkip("ERP not supported in the build")
 
 def test_erp_initiate_reauth_start(dev, apdev):
     """Authenticator sending EAP-Initiate/Re-auth-Start, but ERP disabled on peer"""
@@ -39,9 +49,7 @@
 
 def test_erp(dev, apdev):
     """ERP enabled on server and peer"""
-    capab = dev[0].get_capability("erp")
-    if not capab or 'ERP' not in capab:
-        return "skip"
+    check_erp_capa(dev[0])
     params = int_eap_server_params()
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
@@ -67,9 +75,7 @@
 
 def test_erp_server_no_match(dev, apdev):
     """ERP enabled on server and peer, but server has no key match"""
-    capab = dev[0].get_capability("erp")
-    if not capab or 'ERP' not in capab:
-        return "skip"
+    check_erp_capa(dev[0])
     params = int_eap_server_params()
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
@@ -121,9 +127,7 @@
 
 def test_erp_radius(dev, apdev):
     """ERP enabled on RADIUS server and peer"""
-    capab = dev[0].get_capability("erp")
-    if not capab or 'ERP' not in capab:
-        return "skip"
+    check_erp_capa(dev[0])
     start_erp_as(apdev[1])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "18128"
@@ -171,9 +175,7 @@
 
 def test_erp_radius_eap_methods(dev, apdev):
     """ERP enabled on RADIUS server and peer"""
-    capab = dev[0].get_capability("erp")
-    if not capab or 'ERP' not in capab:
-        return "skip"
+    check_erp_capa(dev[0])
     start_erp_as(apdev[1])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "18128"
@@ -189,9 +191,12 @@
     # TODO: EKE getSession
     #erp_test(dev[0], hapd, eap="EKE", identity="erp-eke@example.com",
     #         password="hello")
-    erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com",
-             password="password", ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
-             phase1="fast_provisioning=2", pac_file="blob://fast_pac_auth_erp")
+    if "FAST" in dev[0].get_capability("eap"):
+        erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com",
+                 password="password", ca_cert="auth_serv/ca.pem",
+                 phase2="auth=GTC",
+                 phase1="fast_provisioning=2",
+                 pac_file="blob://fast_pac_auth_erp")
     erp_test(dev[0], hapd, eap="GPSK", identity="erp-gpsk@example.com",
              password="abcdefghijklmnop0123456789abcdef")
     erp_test(dev[0], hapd, eap="IKEV2", identity="erp-ikev2@example.com",
@@ -204,8 +209,9 @@
     #         phase2="auth=MSCHAPV2")
     erp_test(dev[0], hapd, eap="PSK", identity="erp-psk@example.com",
              password_hex="0123456789abcdef0123456789abcdef")
-    erp_test(dev[0], hapd, eap="PWD", identity="erp-pwd@example.com",
-             password="secret password")
+    if "PWD" in dev[0].get_capability("eap"):
+        erp_test(dev[0], hapd, eap="PWD", identity="erp-pwd@example.com",
+                 password="secret password")
     erp_test(dev[0], hapd, eap="SAKE", identity="erp-sake@example.com",
              password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
     erp_test(dev[0], hapd, eap="SIM", identity="1232010000000000@example.com",
@@ -215,3 +221,187 @@
              private_key="auth_serv/user.key")
     erp_test(dev[0], hapd, eap="TTLS", identity="erp-ttls@example.com",
              password="password", ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+
+def test_erp_key_lifetime_in_memory(dev, apdev, params):
+    """ERP and key lifetime in memory"""
+    check_erp_capa(dev[0])
+    p = int_eap_server_params()
+    p['erp_send_reauth_start'] = '1'
+    p['erp_domain'] = 'example.com'
+    p['eap_server_erp'] = '1'
+    p['disable_pmksa_caching'] = '1'
+    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
+
+    pid = find_wpas_process(dev[0])
+
+    dev[0].request("ERP_FLUSH")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="pap-secret@example.com", password=password,
+                   ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                   erp="1", scan_freq="2412")
+
+    time.sleep(1)
+    buf = read_process_memory(pid, password)
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=15)
+
+    dev[0].relog()
+    msk = None
+    emsk = None
+    rRK = None
+    rIK = None
+    pmk = None
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "EAP-TTLS: Derived key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                msk = binascii.unhexlify(val)
+            if "EAP-TTLS: Derived EMSK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                emsk = binascii.unhexlify(val)
+            if "EAP: ERP rRK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                rRK = binascii.unhexlify(val)
+            if "EAP: ERP rIK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                rIK = binascii.unhexlify(val)
+            if "WPA: PMK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmk = binascii.unhexlify(val)
+            if "WPA: PTK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                ptk = binascii.unhexlify(val)
+            if "WPA: Group Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not msk or not emsk or not rIK or not rRK or not pmk or not ptk or not gtk:
+        raise Exception("Could not find keys from debug log")
+    if len(gtk) != 16:
+        raise Exception("Unexpected GTK length")
+
+    kck = ptk[0:16]
+    kek = ptk[16:32]
+    tk = ptk[32:48]
+
+    fname = os.path.join(params['logdir'],
+                         'erp_key_lifetime_in_memory.memctx-')
+
+    logger.info("Checking keys in memory while associated")
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    get_key_locations(buf, rRK, "rRK")
+    get_key_locations(buf, rIK, "rIK")
+    if password not in buf:
+        raise HwsimSkip("Password not found while associated")
+    if pmk not in buf:
+        raise HwsimSkip("PMK not found while associated")
+    if kck not in buf:
+        raise Exception("KCK not found while associated")
+    if kek not in buf:
+        raise Exception("KEK not found while associated")
+    if tk in buf:
+        raise Exception("TK found from memory")
+    if gtk in buf:
+        raise Exception("GTK found from memory")
+
+    logger.info("Checking keys in memory after disassociation")
+    buf = read_process_memory(pid, password)
+
+    # Note: Password is still present in network configuration
+    # Note: PMK is in EAP fast re-auth data
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    get_key_locations(buf, rRK, "rRK")
+    get_key_locations(buf, rIK, "rIK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+    dev[0].request("RECONNECT")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("EAP success timed out")
+    if "EAP re-authentication completed successfully" not in ev:
+        raise Exception("Did not use ERP")
+    dev[0].wait_connected(timeout=15, error="Reconnection timed out")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=15)
+
+    dev[0].relog()
+    pmk = None
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "WPA: PMK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmk = binascii.unhexlify(val)
+            if "WPA: PTK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                ptk = binascii.unhexlify(val)
+            if "WPA: GTK in EAPOL-Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not pmk or not ptk or not gtk:
+        raise Exception("Could not find keys from debug log")
+
+    kck = ptk[0:16]
+    kek = ptk[16:32]
+    tk = ptk[32:48]
+
+    logger.info("Checking keys in memory after ERP and disassociation")
+    buf = read_process_memory(pid, password)
+
+    # Note: Password is still present in network configuration
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    get_key_locations(buf, rRK, "rRK")
+    get_key_locations(buf, rIK, "rIK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+
+    dev[0].request("REMOVE_NETWORK all")
+
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, password)
+
+    # Note: rRK and rIK are still in memory
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    get_key_locations(buf, msk, "MSK")
+    get_key_locations(buf, emsk, "EMSK")
+    get_key_locations(buf, rRK, "rRK")
+    get_key_locations(buf, rIK, "rIK")
+    verify_not_present(buf, password, fname, "password")
+    verify_not_present(buf, pmk, fname, "PMK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+    verify_not_present(buf, msk, fname, "MSK")
+    verify_not_present(buf, emsk, fname, "EMSK")
+
+    dev[0].request("ERP_FLUSH")
+    logger.info("Checking keys in memory after ERP_FLUSH")
+    buf = read_process_memory(pid, password)
+    get_key_locations(buf, rRK, "rRK")
+    get_key_locations(buf, rIK, "rIK")
+    verify_not_present(buf, rRK, fname, "rRK")
+    verify_not_present(buf, rIK, fname, "rIK")
diff --git a/tests/hwsim/test_gas.py b/tests/hwsim/test_gas.py
index 67c5cea..df11a31 100644
--- a/tests/hwsim/test_gas.py
+++ b/tests/hwsim/test_gas.py
@@ -304,6 +304,12 @@
     if ev is None or "WAN Metrics" not in ev:
         raise Exception("Did not receive WAN Metrics")
 
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE event not seen")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
     if "OK" not in dev[0].request("HS20_ANQP_GET " + bssid + " 3,4"):
         raise Exception("ANQP_GET command failed")
 
@@ -564,10 +570,16 @@
 
     # Station drops invalid frames, but the last of the responses is valid from
     # GAS view point even though it has an extra octet in the end and the ANQP
-    # part of the response is not valid. This is reported as successfulyl
+    # part of the response is not valid. This is reported as successfully
     # completed GAS exchange.
     expect_gas_result(dev[0], "SUCCESS")
 
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE not reported")
+    if "result=INVALID_FRAME" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
 def init_gas(hapd, bssid, dev):
     anqp_get(dev, bssid, 263)
     query = gas_rx(hapd)
diff --git a/tests/hwsim/test_hapd_ctrl.py b/tests/hwsim/test_hapd_ctrl.py
index d06003b..a2d3784 100644
--- a/tests/hwsim/test_hapd_ctrl.py
+++ b/tests/hwsim/test_hapd_ctrl.py
@@ -38,7 +38,7 @@
     params['allow_cross_connection'] = '0'
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
-    addr = dev[0].p2p_dev_addr()
+    addr = dev[0].own_addr()
     if "OK" not in hapd.request("DEAUTHENTICATE " + addr + " p2p=2"):
         raise Exception("DEAUTHENTICATE command failed")
     dev[0].wait_disconnected(timeout=5)
@@ -56,7 +56,7 @@
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
-    addr = dev[0].p2p_dev_addr()
+    addr = dev[0].own_addr()
     if "FAIL" in hapd.request("STA " + addr):
         raise Exception("Unexpected STA failure")
     if "FAIL" not in hapd.request("STA " + addr + " eapol"):
@@ -128,7 +128,7 @@
     if "OK" not in hapd.request("NEW_STA 00:11:22:33:44:55"):
         raise Exception("Unexpected NEW_STA failure")
     if "AUTHORIZED" not in hapd.request("STA 00:11:22:33:44:55"):
-        raise Esception("Unexpected NEW_STA STA status")
+        raise Exception("Unexpected NEW_STA STA status")
 
 def test_hapd_ctrl_get(dev, apdev):
     """hostapd and GET ctrl_iface command"""
diff --git a/tests/hwsim/test_hostapd_oom.py b/tests/hwsim/test_hostapd_oom.py
new file mode 100644
index 0000000..cb91225
--- /dev/null
+++ b/tests/hwsim/test_hostapd_oom.py
@@ -0,0 +1,155 @@
+# hostapd and out-of-memory error paths
+# Copyright (c) 2015, Jouni Malinen
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger()
+import time
+
+import hostapd
+from utils import HwsimSkip
+
+def hostapd_oom_loop(apdev, params, start_func="main"):
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "ctrl" })
+    hapd_global = hostapd.HostapdGlobal()
+
+    count = 0
+    for i in range(1, 1000):
+        if "OK" not in hapd.request("TEST_ALLOC_FAIL %d:%s" % (i, start_func)):
+            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
+        try:
+            hostapd.add_ap(apdev[1]['ifname'], params)
+            logger.info("Iteration %d - success" % i)
+            hapd_global.remove(apdev[1]['ifname'])
+
+            state = hapd.request('GET_ALLOC_FAIL')
+            logger.info("GET_ALLOC_FAIL: " + state)
+            hapd.request("TEST_ALLOC_FAIL 0:")
+            if i < 3:
+                raise Exception("AP setup succeeded during out-of-memory")
+            if state.startswith('0:'):
+                count = 0
+            else:
+                count += 1
+                if count == 5:
+                    break
+        except Exception, e:
+            logger.info("Iteration %d - %s" % (i, str(e)))
+
+def test_hostapd_oom_open(dev, apdev):
+    """hostapd failing to setup open mode due to OOM"""
+    params = { "ssid": "open" }
+    hostapd_oom_loop(apdev, params)
+
+def test_hostapd_oom_wpa2_psk(dev, apdev):
+    """hostapd failing to setup WPA2-PSK mode due to OOM"""
+    params = hostapd.wpa2_params(ssid="test", passphrase="12345678")
+    params['wpa_psk_file'] = 'hostapd.wpa_psk'
+    hostapd_oom_loop(apdev, params)
+
+def test_hostapd_oom_wpa2_eap(dev, apdev):
+    """hostapd failing to setup WPA2-EAP mode due to OOM"""
+    params = hostapd.wpa2_eap_params(ssid="test")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hostapd_oom_loop(apdev, params)
+
+def test_hostapd_oom_wpa2_eap_radius(dev, apdev):
+    """hostapd failing to setup WPA2-EAP mode due to OOM in RADIUS"""
+    params = hostapd.wpa2_eap_params(ssid="test")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hostapd_oom_loop(apdev, params, start_func="accounting_init")
+
+def test_hostapd_oom_wpa2_psk_connect(dev, apdev):
+    """hostapd failing during WPA2-PSK mode connection due to OOM"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].request("SCAN_INTERVAL 1")
+    count = 0
+    for i in range(1, 1000):
+        logger.info("Iteration %d" % i)
+        if "OK" not in hapd.request("TEST_ALLOC_FAIL %d:main" % i):
+            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
+        id = dev[0].connect("test-wpa2-psk", psk="12345678",
+                            scan_freq="2412", wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=5)
+        if ev is None:
+            logger.info("Timeout while waiting for connection in iteration %d" % i)
+            dev[0].request("REMOVE_NETWORK all")
+            time.sleep(0.1)
+        else:
+            if "CTRL-EVENT-SSID-TEMP-DISABLED" in ev:
+                logger.info("Re-select to avoid long wait for temp disavle")
+                dev[0].select_network(id)
+                dev[0].wait_connected()
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+        for i in range(3):
+            dev[i].dump_monitor()
+        hapd.dump_monitor()
+
+        state = hapd.request('GET_ALLOC_FAIL')
+        logger.info("GET_ALLOC_FAIL: " + state)
+        hapd.request("TEST_ALLOC_FAIL 0:")
+        if state.startswith('0:'):
+            count = 0
+        else:
+            count += 1
+            if count == 5:
+                break
+    dev[0].request("SCAN_INTERVAL 5")
+
+def test_hostapd_oom_wpa2_eap_connect(dev, apdev, params):
+    """hostapd failing during WPA2-EAP mode connection due to OOM"""
+    if not params['long']:
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].request("SCAN_INTERVAL 1")
+    count = 0
+    for i in range(1, 1000):
+        logger.info("Iteration %d" % i)
+        if "OK" not in hapd.request("TEST_ALLOC_FAIL %d:main" % i):
+            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
+        id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                            eap="GPSK", identity="gpsk user",
+                            password="abcdefghijklmnop0123456789abcdef",
+                            scan_freq="2412", wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=5)
+        if ev is None:
+            logger.info("Timeout while waiting for connection in iteration %d" % i)
+            dev[0].request("REMOVE_NETWORK all")
+            time.sleep(0.1)
+        else:
+            if "CTRL-EVENT-SSID-TEMP-DISABLED" in ev:
+                logger.info("Re-select to avoid long wait for temp disavle")
+                dev[0].select_network(id)
+                dev[0].wait_connected()
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+        for i in range(3):
+            dev[i].dump_monitor()
+        hapd.dump_monitor()
+
+        state = hapd.request('GET_ALLOC_FAIL')
+        logger.info("GET_ALLOC_FAIL: " + state)
+        hapd.request("TEST_ALLOC_FAIL 0:")
+        if state.startswith('0:'):
+            count = 0
+        else:
+            count += 1
+            if count == 5:
+                break
+    dev[0].request("SCAN_INTERVAL 5")
diff --git a/tests/hwsim/test_ibss.py b/tests/hwsim/test_ibss.py
index b5a8557..5948504 100644
--- a/tests/hwsim/test_ibss.py
+++ b/tests/hwsim/test_ibss.py
@@ -47,7 +47,8 @@
         raise Exception("4-way handshake in IBSS timed out")
 
 def add_ibss(dev, ssid, psk=None, proto=None, key_mgmt=None, pairwise=None,
-             group=None, beacon_int=None, bssid=None, scan_freq=None):
+             group=None, beacon_int=None, bssid=None, scan_freq=None,
+             wep_key0=None):
     id = dev.add_network()
     dev.set_network(id, "mode", "1")
     dev.set_network(id, "frequency", "2412")
@@ -68,12 +69,17 @@
         dev.set_network(id, "beacon_int", beacon_int)
     if bssid:
         dev.set_network(id, "bssid", bssid)
+    if wep_key0:
+        dev.set_network(id, "wep_key0", wep_key0)
     dev.request("ENABLE_NETWORK " + str(id) + " no-connect")
     return id
 
 def add_ibss_rsn(dev, ssid):
     return add_ibss(dev, ssid, "12345678", "RSN", "WPA-PSK", "CCMP", "CCMP")
 
+def add_ibss_rsn_tkip(dev, ssid):
+    return add_ibss(dev, ssid, "12345678", "RSN", "WPA-PSK", "TKIP", "TKIP")
+
 def add_ibss_wpa_none(dev, ssid):
     return add_ibss(dev, ssid, "12345678", "WPA", "WPA-NONE", "TKIP", "TKIP")
 
@@ -308,3 +314,33 @@
         dev[0].request("DISCONNECT")
     finally:
         dev[0].request("AP_SCAN 1")
+
+def test_ibss_rsn_tkip(dev):
+    """IBSS RSN with TKIP as the cipher"""
+    ssid="ibss-rsn-tkip"
+
+    id = add_ibss_rsn_tkip(dev[0], ssid)
+    connect_ibss_cmd(dev[0], id)
+    bssid0 = wait_ibss_connection(dev[0])
+
+    id = add_ibss_rsn_tkip(dev[1], ssid)
+    connect_ibss_cmd(dev[1], id)
+    bssid1 = wait_ibss_connection(dev[1])
+    if bssid0 != bssid1:
+        logger.info("STA0 BSSID " + bssid0 + " differs from STA1 BSSID " + bssid1)
+        # try to merge with a scan
+        dev[1].scan()
+    wait_4way_handshake(dev[0], dev[1])
+    wait_4way_handshake(dev[1], dev[0])
+
+def test_ibss_wep(dev):
+    """IBSS with WEP"""
+    ssid="ibss-wep"
+
+    id = add_ibss(dev[0], ssid, key_mgmt="NONE", wep_key0='"hello"')
+    connect_ibss_cmd(dev[0], id)
+    bssid0 = wait_ibss_connection(dev[0])
+
+    id = add_ibss(dev[1], ssid, key_mgmt="NONE", wep_key0='"hello"')
+    connect_ibss_cmd(dev[1], id)
+    bssid1 = wait_ibss_connection(dev[1])
diff --git a/tests/hwsim/test_ieee8021x.py b/tests/hwsim/test_ieee8021x.py
index 94f60a6..82f783c 100644
--- a/tests/hwsim/test_ieee8021x.py
+++ b/tests/hwsim/test_ieee8021x.py
@@ -23,7 +23,8 @@
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
-                   password_hex="0123456789abcdef0123456789abcdef")
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
 def test_ieee8021x_wep40(dev, apdev):
@@ -37,7 +38,8 @@
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
-                   password_hex="0123456789abcdef0123456789abcdef")
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
 def test_ieee8021x_open(dev, apdev):
@@ -49,7 +51,8 @@
 
     id = dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
                         eap="PSK", identity="psk.user@example.com",
-                        password_hex="0123456789abcdef0123456789abcdef")
+                        password_hex="0123456789abcdef0123456789abcdef",
+                        scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     logger.info("Test EAPOL-Logoff")
@@ -75,5 +78,52 @@
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
                    password_hex="0123456789abcdef0123456789abcdef",
-                   wep_key0='"hello"', eapol_flags="0")
+                   wep_key0='"hello"', eapol_flags="0",
+                   scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ieee8021x_proto(dev, apdev):
+    """IEEE 802.1X and EAPOL supplicant protocol testing"""
+    params = hostapd.radius_params()
+    params["ssid"] = "ieee8021x-open"
+    params["ieee8021x"] = "1"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    bssid = apdev[0]['bssid']
+
+    dev[1].request("SET ext_eapol_frame_io 1")
+    dev[1].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
+                   eap="PSK", identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412", wait_connect=False)
+    id = dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
+                        eap="PSK", identity="psk.user@example.com",
+                        password_hex="0123456789abcdef0123456789abcdef",
+                        scan_freq="2412")
+    ev = dev[1].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+
+    start = dev[0].get_mib()
+
+    tests = [ "11",
+              "11223344",
+              "020000050a93000501",
+              "020300050a93000501",
+              "0203002c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+              "0203002c0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+              "0203002c0100050000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+              "02aa00050a93000501" ]
+    for frame in tests:
+        res = dev[0].request("EAPOL_RX " + bssid + " " + frame)
+        if "OK" not in res:
+            raise Exception("EAPOL_RX to wpa_supplicant failed")
+        dev[1].request("EAPOL_RX " + bssid + " " + frame)
+
+    stop = dev[0].get_mib()
+
+    logger.info("MIB before test frames: " + str(start))
+    logger.info("MIB after test frames: " + str(stop))
+
+    vals = [ 'dot1xSuppInvalidEapolFramesRx',
+             'dot1xSuppEapLengthErrorFramesRx' ]
+    for val in vals:
+        if int(stop[val]) <= int(start[val]):
+            raise Exception(val + " did not increase")
diff --git a/tests/hwsim/test_nfc_p2p.py b/tests/hwsim/test_nfc_p2p.py
index 66de717..88f6a57 100644
--- a/tests/hwsim/test_nfc_p2p.py
+++ b/tests/hwsim/test_nfc_p2p.py
@@ -19,10 +19,10 @@
                   "WPS-FAIL"]
 
 def set_ip_addr_info(dev):
-    dev.request("SET ip_addr_go 192.168.42.1")
-    dev.request("SET ip_addr_mask 255.255.255.0")
-    dev.request("SET ip_addr_start 192.168.42.100")
-    dev.request("SET ip_addr_end 192.168.42.199")
+    dev.global_request("SET ip_addr_go 192.168.42.1")
+    dev.global_request("SET ip_addr_mask 255.255.255.0")
+    dev.global_request("SET ip_addr_start 192.168.42.100")
+    dev.global_request("SET ip_addr_end 192.168.42.199")
 
 def check_ip_addr(res):
     if 'ip_addr' not in res:
@@ -41,35 +41,38 @@
 def test_nfc_p2p_go_neg(dev):
     """NFC connection handover to form a new P2P group (initiator becomes GO)"""
     set_ip_addr_info(dev[0])
-    dev[0].request("SET p2p_go_intent 10")
+    ip = dev[0].request("GET ip_addr_go")
+    if ip != "192.168.42.1":
+        raise Exception("Unexpected ip_addr_go returned: " + ip)
+    dev[0].global_request("SET p2p_go_intent 10")
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[0].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=1)
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -83,35 +86,35 @@
 def test_nfc_p2p_go_neg_reverse(dev):
     """NFC connection handover to form a new P2P group (responder becomes GO)"""
     set_ip_addr_info(dev[1])
-    dev[0].request("SET p2p_go_intent 3")
+    dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[0].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=1)
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -128,22 +131,22 @@
     logger.info("Start autonomous GO")
     dev[0].p2p_start_go()
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[1].wait_event(["P2P-GROUP-STARTED"], timeout=15)
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
         raise Exception("Connection to the group timed out")
     res1 = dev[1].group_form_result(ev)
@@ -158,22 +161,22 @@
     logger.info("Start autonomous GO")
     dev[1].p2p_start_go()
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[0].wait_event(["P2P-GROUP-STARTED"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
         raise Exception("Connection to the group timed out")
     res0 = dev[0].group_form_result(ev)
@@ -266,36 +269,36 @@
 
     logger.info("Perform NFC connection handover")
 
-    res = dev[1].request("SET p2p_listen_reg_class 81")
-    res2 = dev[1].request("SET p2p_listen_channel 6")
+    res = dev[1].global_request("SET p2p_listen_reg_class 81")
+    res2 = dev[1].global_request("SET p2p_listen_channel 6")
     if "FAIL" in res or "FAIL" in res2:
         raise Exception("Could not set Listen channel")
-    pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[1].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    res = dev[1].request("P2P_SET nfc_tag 1").rstrip()
+    res = dev[1].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
-    res = dev[1].request("P2P_LISTEN")
+    res = dev[1].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
     dev[1].dump_monitor()
 
     dev[0].dump_monitor()
-    dev[0].request("SET p2p_go_intent 10")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+    dev[0].global_request("SET p2p_go_intent 10")
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[0].wait_event(grpform_events, timeout=15)
+    ev = dev[0].wait_global_event(grpform_events, timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(grpform_events, timeout=1)
+    ev = dev[1].wait_global_event(grpform_events, timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -313,37 +316,37 @@
 
     logger.info("Perform NFC connection handover")
 
-    res = dev[1].request("SET p2p_listen_reg_class 81")
-    res2 = dev[1].request("SET p2p_listen_channel 6")
+    res = dev[1].global_request("SET p2p_listen_reg_class 81")
+    res2 = dev[1].global_request("SET p2p_listen_channel 6")
     if "FAIL" in res or "FAIL" in res2:
         raise Exception("Could not set Listen channel")
-    pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[1].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    dev[1].request("SET p2p_no_group_iface 0")
-    res = dev[1].request("P2P_SET nfc_tag 1").rstrip()
+    dev[1].global_request("SET p2p_no_group_iface 0")
+    res = dev[1].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
-    res = dev[1].request("P2P_LISTEN")
+    res = dev[1].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
     dev[1].dump_monitor()
 
     dev[0].dump_monitor()
-    dev[0].request("SET p2p_go_intent 10")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+    dev[0].global_request("SET p2p_go_intent 10")
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[0].wait_event(grpform_events, timeout=15)
+    ev = dev[0].wait_global_event(grpform_events, timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(grpform_events, timeout=1)
+    ev = dev[1].wait_global_event(grpform_events, timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -361,36 +364,36 @@
 
     logger.info("Perform NFC connection handover")
 
-    res = dev[1].request("SET p2p_listen_reg_class 81")
-    res2 = dev[1].request("SET p2p_listen_channel 6")
+    res = dev[1].global_request("SET p2p_listen_reg_class 81")
+    res2 = dev[1].global_request("SET p2p_listen_channel 6")
     if "FAIL" in res or "FAIL" in res2:
         raise Exception("Could not set Listen channel")
-    pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[1].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    res = dev[1].request("P2P_SET nfc_tag 1").rstrip()
+    res = dev[1].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
-    res = dev[1].request("P2P_LISTEN")
+    res = dev[1].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
     dev[1].dump_monitor()
 
     dev[0].dump_monitor()
-    dev[0].request("SET p2p_go_intent 3")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+    dev[0].global_request("SET p2p_go_intent 3")
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[0].wait_event(grpform_events, timeout=15)
+    ev = dev[0].wait_global_event(grpform_events, timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(grpform_events, timeout=1)
+    ev = dev[1].wait_global_event(grpform_events, timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -408,36 +411,36 @@
 
     logger.info("Perform NFC connection handover")
 
-    res = dev[1].request("SET p2p_listen_reg_class 81")
-    res2 = dev[1].request("SET p2p_listen_channel 6")
+    res = dev[1].global_request("SET p2p_listen_reg_class 81")
+    res2 = dev[1].global_request("SET p2p_listen_channel 6")
     if "FAIL" in res or "FAIL" in res2:
         raise Exception("Could not set Listen channel")
-    pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[1].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    res = dev[1].request("P2P_SET nfc_tag 1").rstrip()
+    res = dev[1].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
-    res = dev[1].request("P2P_LISTEN")
+    res = dev[1].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
     dev[1].dump_monitor()
 
     dev[0].dump_monitor()
-    dev[0].request("SET p2p_go_intent 3")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel + " freq=2442")
+    dev[0].global_request("SET p2p_go_intent 3")
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel + " freq=2442")
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[0].wait_event(grpform_events, timeout=15)
+    ev = dev[0].wait_global_event(grpform_events, timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(grpform_events, timeout=1)
+    ev = dev[1].wait_global_event(grpform_events, timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -496,29 +499,29 @@
     logger.info("Start autonomous GO")
     dev[0].p2p_start_go()
 
-    dev[1].request("SET ignore_old_scan_res 1")
-    dev[2].request("SET ignore_old_scan_res 1")
+    dev[1].global_request("SET ignore_old_scan_res 1")
+    dev[2].global_request("SET ignore_old_scan_res 1")
 
     logger.info("Write NFC Tag on the P2P Client")
-    res = dev[1].request("P2P_LISTEN")
+    res = dev[1].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
-    pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[1].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    res = dev[1].request("P2P_SET nfc_tag 1").rstrip()
+    res = dev[1].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
 
     logger.info("Read NFC Tag on the GO to trigger invitation")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[1].wait_event(grpform_events, timeout=30)
+    ev = dev[1].wait_global_event(grpform_events, timeout=30)
     if ev is None:
         raise Exception("Joining the group timed out")
     res = dev[1].group_form_result(ev)
@@ -526,25 +529,25 @@
     check_ip_addr(res)
 
     logger.info("Write NFC Tag on another P2P Client")
-    res = dev[2].request("P2P_LISTEN")
+    res = dev[2].global_request("P2P_LISTEN")
     if "FAIL" in res:
         raise Exception("Failed to start Listen mode")
-    pw = dev[2].request("WPS_NFC_TOKEN NDEF").rstrip()
+    pw = dev[2].global_request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
         raise Exception("Failed to generate password token")
-    res = dev[2].request("P2P_SET nfc_tag 1").rstrip()
+    res = dev[2].global_request("P2P_SET nfc_tag 1").rstrip()
     if "FAIL" in res:
         raise Exception("Failed to enable NFC Tag for P2P static handover")
-    sel = dev[2].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    sel = dev[2].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
 
     logger.info("Read NFC Tag on the GO to trigger invitation")
-    res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+    res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
     if "FAIL" in res:
         raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
 
-    ev = dev[2].wait_event(grpform_events, timeout=30)
+    ev = dev[2].wait_global_event(grpform_events, timeout=30)
     if ev is None:
         raise Exception("Joining the group timed out")
     res = dev[2].group_form_result(ev)
@@ -556,7 +559,7 @@
     logger.info("Start autonomous GOs")
     dev[0].p2p_start_go()
     logger.info("Connect legacy WPS STA with configuration token")
-    conf = dev[0].request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
+    conf = dev[0].group_request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
     if "FAIL" in conf:
         raise Exception("Failed to generate configuration token")
     dev[1].dump_monitor()
@@ -576,10 +579,10 @@
     req = dev[1].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[0].request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
+    sel = dev[0].group_request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
-    res = dev[0].request("NFC_REPORT_HANDOVER RESP WPS " + req + " " + sel)
+    res = dev[0].group_request("NFC_REPORT_HANDOVER RESP WPS " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant (GO)")
     dev[1].dump_monitor()
@@ -594,35 +597,35 @@
 def test_nfc_p2p_ip_addr_assignment(dev):
     """NFC connection handover and legacy station IP address assignment"""
     set_ip_addr_info(dev[1])
-    dev[0].request("SET p2p_go_intent 3")
+    dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[0].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=1)
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
@@ -634,13 +637,14 @@
     check_ip_addr(res0)
 
     logger.info("Connect legacy P2P client that does not use new IP address assignment")
-    res = dev[2].request("P2P_SET disable_ip_addr_req 1")
+    res = dev[2].global_request("P2P_SET disable_ip_addr_req 1")
     if "FAIL" in res:
         raise Exception("Failed to disable IP address assignment request")
     pin = dev[2].wps_read_pin()
     dev[1].p2p_go_authorize_client(pin)
     res = dev[2].p2p_connect_group(dev[1].p2p_dev_addr(), pin, timeout=60)
     logger.info("Client connected")
+    res = dev[2].global_request("P2P_SET disable_ip_addr_req 0")
     hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
     if 'ip_addr' in res:
         raise Exception("Unexpected IP address assignment")
@@ -648,35 +652,35 @@
 def test_nfc_p2p_ip_addr_assignment2(dev):
     """NFC connection handover and IP address assignment for two clients"""
     set_ip_addr_info(dev[1])
-    dev[0].request("SET p2p_go_intent 3")
+    dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
-    req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
     if "FAIL" in req:
         raise Exception("Failed to generate NFC connection handover request")
-    sel = dev[1].request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
     dev[0].dump_monitor()
     dev[1].dump_monitor()
-    res = dev[1].request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
+    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
-    res = dev[0].request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
+    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
     if "FAIL" in res:
         raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
 
-    ev = dev[0].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=15)
     if ev is None:
         raise Exception("Group formation timed out")
     res0 = dev[0].group_form_result(ev)
 
-    ev = dev[1].wait_event(["P2P-GROUP-STARTED",
-                            "P2P-GO-NEG-FAILURE",
-                            "P2P-GROUP-FORMATION-FAILURE",
-                            "WPS-PIN-NEEDED"], timeout=1)
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED",
+                                   "P2P-GO-NEG-FAILURE",
+                                   "P2P-GROUP-FORMATION-FAILURE",
+                                   "WPS-PIN-NEEDED"], timeout=1)
     if ev is None:
         raise Exception("Group formation timed out")
     res1 = dev[1].group_form_result(ev)
diff --git a/tests/hwsim/test_nfc_wps.py b/tests/hwsim/test_nfc_wps.py
index 75d06e2..9a8255b 100644
--- a/tests/hwsim/test_nfc_wps.py
+++ b/tests/hwsim/test_nfc_wps.py
@@ -245,7 +245,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_nfc_wps_handover_chan14(dev, apdev):
@@ -277,7 +277,7 @@
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_nfc_wps_handover_with_pw_token_set(dev, apdev):
@@ -546,3 +546,20 @@
         raise Exception("Timed out")
     if "WPS-FAIL" not in ev:
         raise Exception("Public key hash mismatch not detected")
+
+def test_nfc_invalid_ndef_record(dev, apdev):
+    """Invalid NFC NDEF record handling"""
+    tests = [ "11223344",
+              "00112233",
+              "0000112233445566",
+              "0800112233445566",
+              "080011223344",
+              "18000000",
+              "18010000",
+              "90000050",
+              "9000005000",
+              "9001013344",
+              "98010101334455" ]
+    for test in tests:
+        if "FAIL" not in dev[0].request("WPS_NFC_TAG_READ " + test):
+            raise Exception("Invalid tag accepted: " + test)
diff --git a/tests/hwsim/test_offchannel_tx.py b/tests/hwsim/test_offchannel_tx.py
index 2a247c6..6d49392 100644
--- a/tests/hwsim/test_offchannel_tx.py
+++ b/tests/hwsim/test_offchannel_tx.py
@@ -22,7 +22,8 @@
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="no_offchannel_tx=1")
-    wpas.scan(freq="2412")
+    wpas.flush_scan_cache()
+    wpas.scan_for_bss(bssid, freq=2412)
     anqp_get(wpas, bssid, 263)
     ev = wpas.wait_event(["GAS-QUERY-DONE"], timeout=10)
     if ev is None:
diff --git a/tests/hwsim/test_p2p_autogo.py b/tests/hwsim/test_p2p_autogo.py
index 1ab5acd..234e8f3 100644
--- a/tests/hwsim/test_p2p_autogo.py
+++ b/tests/hwsim/test_p2p_autogo.py
@@ -1,5 +1,5 @@
 # P2P autonomous GO test cases
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, 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 @@
 
 import hwsim_utils
 import utils
+from utils import HwsimSkip
 from wlantest import Wlantest
 from wpasupplicant import WpaSupplicant
 
@@ -40,14 +41,14 @@
     res = connect_cli(dev[0], dev[1])
     if "p2p-wlan" in res['ifname']:
         raise Exception("Unexpected group interface name on client")
-    bss = dev[1].get_bss("p2p_dev_addr=" + addr0)
-    if bss['bssid'] != dev[0].p2p_interface_addr():
+    bss = dev[1].get_bss("p2p_dev_addr=" + addr0, res['ifname'])
+    if not bss or bss['bssid'] != dev[0].p2p_interface_addr():
         raise Exception("Unexpected BSSID in the BSS entry for the GO")
     id = bss['id']
-    bss = dev[1].get_bss("ID-" + id)
-    if bss['id'] != id:
+    bss = dev[1].get_bss("ID-" + id, res['ifname'])
+    if not bss or bss['id'] != id:
         raise Exception("Could not find BSS entry based on id")
-    res = dev[1].request("BSS RANGE=" + id + "- MASK=0x1")
+    res = dev[1].group_request("BSS RANGE=" + id + "- MASK=0x1")
     if "id=" + id not in res:
         raise Exception("Could not find BSS entry based on id range")
 
@@ -62,7 +63,7 @@
         raise Exception("Invald P2P_PRESENCE_REQ accepted")
     if "FAIL" in dev[1].group_request("P2P_PRESENCE_REQ 30000 102400"):
         raise Exception("Could not send presence request")
-    ev = dev[1].wait_event(["P2P-PRESENCE-RESPONSE"])
+    ev = dev[1].wait_group_event(["P2P-PRESENCE-RESPONSE"], 10)
     if ev is None:
         raise Exception("Timeout while waiting for Presence Response")
     if "FAIL" in dev[1].group_request("P2P_PRESENCE_REQ 30000 102400 20000 102400"):
@@ -298,7 +299,7 @@
     res = autogo(dev[0], freq=2462)
     if dev[0].get_group_status_field("passphrase", extra="WPS") != res['passphrase']:
         raise Exception("passphrase mismatch")
-    if dev[0].request("P2P_GET_PASSPHRASE") != res['passphrase']:
+    if dev[0].group_request("P2P_GET_PASSPHRASE") != res['passphrase']:
         raise Exception("passphrase mismatch(2)")
 
     logger.info("Connect P2P client")
@@ -340,7 +341,7 @@
     if "FAIL" in res:
         # for now, skip test since mac80211_hwsim support is not yet widely
         # deployed
-        return 'skip'
+        raise HwsimSkip("Assume mac80211_hwsim did not support channel switching")
     ev = dev[0].wait_event(["AP-CSA-FINISHED"], timeout=10)
     if ev is None:
         raise Exception("CSA finished event timed out")
@@ -370,7 +371,7 @@
     wpas.interface_add("wlan5")
     res = autogo(wpas)
     wpas.dump_monitor()
-    subprocess.call(['sudo', 'ifconfig', res['ifname'], 'down'])
+    subprocess.call(['ifconfig', res['ifname'], 'down'])
     ev = wpas.wait_global_event(["P2P-GROUP-REMOVED"], timeout=10)
     if ev is None:
         raise Exception("Group removal not reported")
@@ -437,29 +438,30 @@
         if "OK" not in dev[0].request("AUTOSCAN periodic:1"):
             raise Exception("Failed to set autoscan")
         autogo(dev[0])
-        subprocess.call(['sudo', 'brctl', 'addbr', 'p2p-br0'])
-        subprocess.call(['sudo', 'brctl', 'setfd', 'p2p-br0', '0'])
-        subprocess.call(['sudo', 'brctl', 'addif', 'p2p-br0', dev[0].ifname])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'p2p-br0', 'up'])
+        ifname = dev[0].get_group_ifname()
+        subprocess.call(['brctl', 'addbr', 'p2p-br0'])
+        subprocess.call(['brctl', 'setfd', 'p2p-br0', '0'])
+        subprocess.call(['brctl', 'addif', 'p2p-br0', ifname])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'p2p-br0', 'up'])
         time.sleep(0.1)
-        subprocess.call(['sudo', 'brctl', 'delif', 'p2p-br0', dev[0].ifname])
+        subprocess.call(['brctl', 'delif', 'p2p-br0', ifname])
         time.sleep(0.1)
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'p2p-br0', 'down'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down'])
         time.sleep(0.1)
-        subprocess.call(['sudo', 'brctl', 'delbr', 'p2p-br0'])
+        subprocess.call(['brctl', 'delbr', 'p2p-br0'])
         ev = dev[0].wait_global_event(["P2P-GROUP-REMOVED"], timeout=1)
         if ev is not None:
             raise Exception("P2P group removed unexpectedly")
-        if dev[0].get_status_field('wpa_state') != "COMPLETED":
+        if dev[0].get_group_status_field('wpa_state') != "COMPLETED":
             raise Exception("Unexpected wpa_state")
         dev[0].remove_group()
     finally:
         dev[0].request("AUTOSCAN ")
-        subprocess.Popen(['sudo', 'brctl', 'delif', 'p2p-br0', dev[0].ifname],
+        subprocess.Popen(['brctl', 'delif', 'p2p-br0', ifname],
                          stderr=open('/dev/null', 'w'))
-        subprocess.Popen(['sudo', 'ip', 'link', 'set', 'dev', 'p2p-br0', 'down'],
+        subprocess.Popen(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down'],
                          stderr=open('/dev/null', 'w'))
-        subprocess.Popen(['sudo', 'brctl', 'delbr', 'p2p-br0'],
+        subprocess.Popen(['brctl', 'delbr', 'p2p-br0'],
                          stderr=open('/dev/null', 'w'))
 
 def test_presence_req_on_group_interface(dev):
@@ -474,3 +476,228 @@
         raise Exception("Timeout while waiting for Presence Response")
     dev[0].remove_group()
     dev[1].wait_go_ending_session()
+
+def test_autogo_join_auto_go_not_found(dev):
+    """P2P_CONNECT-auto not finding GO"""
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("P2P_SET listen_channel 1")
+    wpas.global_request("SET p2p_no_group_iface 0")
+    autogo(wpas, freq=2412)
+    addr = wpas.p2p_dev_addr()
+    bssid = wpas.p2p_interface_addr()
+
+    dev[1].global_request("SET p2p_no_group_iface 0")
+    dev[1].scan_for_bss(bssid, freq=2412)
+    # This makes the GO not show up in the scan iteration following the
+    # P2P_CONNECT command by stopping beaconing and handling Probe Request
+    # frames externally (but not really replying to them). P2P listen mode is
+    # needed to keep the GO listening on the operating channel for the PD
+    # exchange.
+    if "OK" not in wpas.group_request("STOP_AP"):
+        raise Exception("STOP_AP failed")
+    wpas.group_request("SET ext_mgmt_frame_handling 1")
+    wpas.p2p_listen()
+    time.sleep(0.02)
+    dev[1].global_request("P2P_CONNECT " + addr + " pbc auto")
+
+    ev = dev[1].wait_group_event(["P2P-FALLBACK-TO-GO-NEG-ENABLED"], 15)
+    if ev is None:
+        raise Exception("Could not trigger old-scan-only case")
+        return
+
+    ev = dev[1].wait_group_event(["P2P-FALLBACK-TO-GO-NEG"], 15)
+    wpas.remove_group()
+    if ev is None:
+        raise Exception("Fallback to GO Negotiation not seen")
+    if "reason=GO-not-found" not in ev:
+        raise Exception("Unexpected reason for fallback: " + ev)
+
+def test_autogo_join_auto(dev):
+    """P2P_CONNECT-auto joining a group"""
+    autogo(dev[0])
+    addr = dev[0].p2p_dev_addr()
+    if "OK" not in dev[1].global_request("P2P_CONNECT " + addr + " pbc auto"):
+        raise Exception("P2P_CONNECT failed")
+
+    ev = dev[0].wait_global_event(["P2P-PROV-DISC-PBC-REQ"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on P2P-PROV-DISC-PBC-REQ")
+    if "group=" + dev[0].group_ifname not in ev:
+        raise Exception("Unexpected PD event contents: " + ev)
+    dev[0].group_request("WPS_PBC")
+
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Joining the group timed out")
+    dev[1].group_form_result(ev)
+
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+    dev[1].flush_scan_cache()
+
+def test_autogo_join_auto_go_neg(dev):
+    """P2P_CONNECT-auto fallback to GO Neg"""
+    dev[1].flush_scan_cache()
+    dev[0].p2p_listen()
+    addr = dev[0].p2p_dev_addr()
+    if "OK" not in dev[1].global_request("P2P_CONNECT " + addr + " pbc auto"):
+        raise Exception("P2P_CONNECT failed")
+
+    ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on P2P-GO-NEG-REQUEST")
+    peer = ev.split(' ')[1]
+    dev[0].p2p_go_neg_init(peer, None, "pbc", timeout=15, go_intent=15)
+
+    ev = dev[1].wait_global_event(["P2P-FALLBACK-TO-GO-NEG"], timeout=1)
+    if ev is None:
+        raise Exception("No P2P-FALLBACK-TO-GO-NEG event seen")
+    if "P2P-FALLBACK-TO-GO-NEG-ENABLED" in ev:
+        ev = dev[1].wait_global_event(["P2P-FALLBACK-TO-GO-NEG"], timeout=1)
+        if ev is None:
+            raise Exception("No P2P-FALLBACK-TO-GO-NEG event seen")
+    if "reason=peer-not-running-GO" not in ev:
+        raise Exception("Unexpected reason: " + ev)
+
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Joining the group timed out")
+    dev[1].group_form_result(ev)
+
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+    dev[1].flush_scan_cache()
+
+def test_autogo_join_auto_go_neg_after_seeing_go(dev):
+    """P2P_CONNECT-auto fallback to GO Neg after seeing GO"""
+    autogo(dev[0], freq=2412)
+    addr = dev[0].p2p_dev_addr()
+    bssid = dev[0].p2p_interface_addr()
+    dev[1].scan_for_bss(bssid, freq=2412)
+    dev[0].remove_group()
+    dev[0].p2p_listen()
+
+    if "OK" not in dev[1].global_request("P2P_CONNECT " + addr + " pbc auto"):
+        raise Exception("P2P_CONNECT failed")
+
+    ev = dev[1].wait_global_event(["P2P-FALLBACK-TO-GO-NEG-ENABLED"],
+                                  timeout=15)
+    if ev is None:
+        raise Exception("No P2P-FALLBACK-TO-GO-NEG-ENABLED event seen")
+
+    ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on P2P-GO-NEG-REQUEST")
+    peer = ev.split(' ')[1]
+    dev[0].p2p_go_neg_init(peer, None, "pbc", timeout=15, go_intent=15)
+
+    ev = dev[1].wait_global_event(["P2P-FALLBACK-TO-GO-NEG"], timeout=1)
+    if ev is None:
+        raise Exception("No P2P-FALLBACK-TO-GO-NEG event seen")
+    if "reason=no-ACK-to-PD-Req" not in ev and "reason=PD-failed" not in ev:
+        raise Exception("Unexpected reason: " + ev)
+
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Joining the group timed out")
+    dev[1].group_form_result(ev)
+
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+    dev[1].flush_scan_cache()
+
+def test_go_search_non_social(dev):
+    """P2P_FIND with freq parameter to scan a single channel"""
+    addr0 = dev[0].p2p_dev_addr()
+    autogo(dev[0], freq=2422)
+    dev[1].p2p_find(freq=2422)
+    ev = dev[1].wait_event(["P2P-DEVICE-FOUND"], timeout=3.5)
+    if ev is None:
+        raise Exception("Did not find GO quickly enough")
+    dev[2].p2p_listen()
+    ev = dev[1].wait_event(["P2P-DEVICE-FOUND"], timeout=5)
+    if ev is None:
+        raise Exception("Did not find peer")
+    dev[2].p2p_stop_find()
+    dev[1].p2p_stop_find()
+    dev[0].remove_group()
+
+def test_autogo_many(dev):
+    """P2P autonomous GO with large number of GO instances"""
+    dev[0].request("SET p2p_no_group_iface 0")
+    for i in range(100):
+        if "OK" not in dev[0].global_request("P2P_GROUP_ADD freq=2412"):
+            logger.info("Was able to add %d groups" % i)
+            if i < 5:
+                raise Exception("P2P_GROUP_ADD failed")
+            stop_ev = dev[0].wait_global_event(["P2P-GROUP-REMOVE"], timeout=1)
+            if stop_ev is not None:
+                raise Exception("Unexpected P2P-GROUP-REMOVE event")
+            break
+        ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("GO start up timed out")
+        dev[0].group_form_result(ev)
+
+    for i in dev[0].global_request("INTERFACES").splitlines():
+        dev[0].request("P2P_GROUP_REMOVE " + i)
+        dev[0].dump_monitor()
+    dev[0].request("P2P_GROUP_REMOVE *")
+
+def test_autogo_many_clients(dev):
+    """P2P autonomous GO and many clients (P2P IE fragmentation)"""
+    try:
+        _test_autogo_many_clients(dev)
+    finally:
+        dev[0].request("SET device_name Device A")
+        dev[1].request("SET device_name Device B")
+        dev[2].request("SET device_name Device C")
+
+def _test_autogo_many_clients(dev):
+    # These long device names will push the P2P IE contents beyond the limit
+    # that requires fragmentation.
+    name0 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    name1 = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+    name2 = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
+    name3 = "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
+    dev[0].request("SET device_name " + name0)
+    dev[1].request("SET device_name " + name1)
+    dev[2].request("SET device_name " + name2)
+
+    addr0 = dev[0].p2p_dev_addr()
+    res = autogo(dev[0], freq=2412)
+    bssid = dev[0].p2p_interface_addr()
+
+    connect_cli(dev[0], dev[1], social=True, freq=2412)
+    dev[0].dump_monitor()
+    connect_cli(dev[0], dev[2], social=True, freq=2412)
+    dev[0].dump_monitor()
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("SET device_name " + name3)
+    wpas.request("SET sec_device_type 1-11111111-1")
+    wpas.request("SET sec_device_type 2-22222222-2")
+    wpas.request("SET sec_device_type 3-33333333-3")
+    wpas.request("SET sec_device_type 4-44444444-4")
+    wpas.request("SET sec_device_type 5-55555555-5")
+    connect_cli(dev[0], wpas, social=True, freq=2412)
+    dev[0].dump_monitor()
+
+    dev[1].dump_monitor()
+    dev[1].p2p_find(freq=2412)
+    ev1 = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev1 is None:
+        raise Exception("Could not find peer (1)")
+    ev2 = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev2 is None:
+        raise Exception("Could not find peer (2)")
+    ev3 = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev3 is None:
+        raise Exception("Could not find peer (3)")
+    dev[1].p2p_stop_find()
+
+    for i in [ name0, name2, name3 ]:
+        if i not in ev1 and i not in ev2 and i not in ev3:
+            raise Exception('name "%s" not found' % i)
diff --git a/tests/hwsim/test_p2p_channel.py b/tests/hwsim/test_p2p_channel.py
index 19cad6e..d89159a 100644
--- a/tests/hwsim/test_p2p_channel.py
+++ b/tests/hwsim/test_p2p_channel.py
@@ -12,6 +12,7 @@
 
 import hostapd
 import hwsim_utils
+from tshark import run_tshark
 from wpasupplicant import WpaSupplicant
 from hwsim import HWSimRadio
 from test_p2p_grpform import go_neg_pin_authorized
@@ -21,7 +22,7 @@
 from test_p2p_autogo import autogo
 
 def set_country(country, dev=None):
-    subprocess.call(['sudo', 'iw', 'reg', 'set', country])
+    subprocess.call(['iw', 'reg', 'set', country])
     time.sleep(0.1)
     if dev:
         for i in range(10):
@@ -131,28 +132,9 @@
             raise Exception("Unexpected channel %d MHz - did not pick random social channel" % freq)
         remove_group(dev[0], dev[1])
 
-        try:
-            arg = [ "tshark",
-                    "-r", os.path.join(params['logdir'], "hwsim0.pcapng"),
-                    "-Y", "wifi_p2p.public_action.subtype == 0",
-                    "-V" ]
-            cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
-                                   stderr=open('/dev/null', 'w'))
-        except Exception, e:
-            logger.info("Could run run tshark check: " + str(e))
-            cmd = None
-            pass
-
-        if cmd:
-            (out,err) = cmd.communicate()
-            res = cmd.wait()
-            if res == 1:
-                arg[3] = '-R'
-                cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
-                                       stderr=open('/dev/null', 'w'))
-                (out,err) = cmd.communicate()
-                res = cmd.wait()
-
+        out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                         "wifi_p2p.public_action.subtype == 0")
+        if out is not None:
             last = None
             for l in out.splitlines():
                 if "Operating Channel:" not in l:
@@ -191,7 +173,7 @@
         ev = dev[0].wait_event(["CTRL-EVENT-AVOID-FREQ"], timeout=10)
         if ev is None:
             raise Exception("No CTRL-EVENT-AVOID-FREQ event")
-        ev = dev[0].wait_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=1)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=1)
         if ev is not None:
             raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP event")
 
@@ -200,7 +182,8 @@
         ev = dev[0].wait_event(["CTRL-EVENT-AVOID-FREQ"], timeout=10)
         if ev is None:
             raise Exception("No CTRL-EVENT-AVOID-FREQ event")
-        ev = dev[0].wait_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=10)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"],
+                                     timeout=10)
         if ev is None:
             raise Exception("No P2P-REMOVE-AND-REFORM-GROUP event")
     finally:
@@ -592,3 +575,85 @@
         _test_autogo_ht_vht(dev)
     finally:
         set_country("00")
+
+def test_p2p_listen_chan_optimize(dev, apdev):
+    """P2P listen channel optimization"""
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    addr5 = wpas.p2p_dev_addr()
+    try:
+        if "OK" not in wpas.request("SET p2p_optimize_listen_chan 1"):
+            raise Exception("Failed to set p2p_optimize_listen_chan")
+        wpas.p2p_listen()
+        if not dev[0].discover_peer(addr5):
+            raise Exception("Could not discover peer")
+        peer = dev[0].get_peer(addr5)
+        lfreq = peer['listen_freq']
+        wpas.p2p_stop_find()
+        dev[0].p2p_stop_find()
+
+        channel = "1" if lfreq != '2412' else "6"
+        freq = "2412" if lfreq != '2412' else "2437"
+        params = { "ssid": "test-open", "channel": channel }
+        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+        id = wpas.connect("test-open", key_mgmt="NONE", scan_freq=freq)
+        wpas.p2p_listen()
+
+        if "OK" not in dev[0].request("P2P_FLUSH"):
+            raise Exception("P2P_FLUSH failed")
+        if not dev[0].discover_peer(addr5):
+            raise Exception("Could not discover peer")
+        peer = dev[0].get_peer(addr5)
+        lfreq2 = peer['listen_freq']
+        if lfreq == lfreq2:
+            raise Exception("Listen channel did not change")
+        if lfreq2 != freq:
+            raise Exception("Listen channel not on AP's operating channel")
+        wpas.p2p_stop_find()
+        dev[0].p2p_stop_find()
+
+        wpas.request("DISCONNECT")
+        wpas.wait_disconnected()
+
+        # for larger coverage, cover case of current channel matching
+        wpas.select_network(id)
+        wpas.wait_connected()
+        wpas.request("DISCONNECT")
+        wpas.wait_disconnected()
+
+        lchannel = "1" if channel != "1" else "6"
+        lfreq3 = "2412" if channel != "1" else "2437"
+        if "OK" not in wpas.request("P2P_SET listen_channel " + lchannel):
+            raise Exception("Failed to set listen channel")
+
+        wpas.select_network(id)
+        wpas.wait_connected()
+        wpas.p2p_listen()
+
+        if "OK" not in dev[0].request("P2P_FLUSH"):
+            raise Exception("P2P_FLUSH failed")
+        if not dev[0].discover_peer(addr5):
+            raise Exception("Could not discover peer")
+        peer = dev[0].get_peer(addr5)
+        lfreq4 = peer['listen_freq']
+        if lfreq4 != lfreq3:
+            raise Exception("Unexpected Listen channel after configuration")
+        wpas.p2p_stop_find()
+        dev[0].p2p_stop_find()
+    finally:
+        wpas.request("SET p2p_optimize_listen_chan 0")
+
+def test_p2p_channel_5ghz_only(dev):
+    """P2P GO start with only 5 GHz band allowed"""
+    try:
+        set_country("US", dev[0])
+        dev[0].request("P2P_SET disallow_freq 2400-2500")
+        res = autogo(dev[0])
+        freq = int(res['freq'])
+        if freq < 5000:
+            raise Exception("Unexpected channel %d MHz" % freq)
+        dev[0].remove_group()
+    finally:
+        set_country("00")
+        dev[0].request("P2P_SET disallow_freq ")
diff --git a/tests/hwsim/test_p2p_concurrency.py b/tests/hwsim/test_p2p_concurrency.py
index 612b85a..a3b50f5 100644
--- a/tests/hwsim/test_p2p_concurrency.py
+++ b/tests/hwsim/test_p2p_concurrency.py
@@ -43,11 +43,11 @@
 
 def test_concurrent_autogo_crossconnect(dev, apdev):
     """Concurrent P2P autonomous GO"""
-    dev[0].request("P2P_SET cross_connect 1")
+    dev[0].global_request("P2P_SET cross_connect 1")
     hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
 
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].p2p_start_go(no_event_clear=True)
     ev = dev[0].wait_global_event("P2P-CROSS-CONNECT-ENABLE", timeout=10)
     if ev is None:
@@ -56,7 +56,7 @@
         raise Exception("Unexpected interfaces: " + ev)
     dev[0].dump_monitor()
 
-    dev[0].request("P2P_SET cross_connect 0")
+    dev[0].global_request("P2P_SET cross_connect 0")
     ev = dev[0].wait_global_event("P2P-CROSS-CONNECT-DISABLE", timeout=10)
     if ev is None:
         raise Exception("Timeout on cross connection disabled event")
@@ -64,7 +64,7 @@
         raise Exception("Unexpected interfaces: " + ev)
     dev[0].remove_group()
 
-    dev[0].request("P2P_SET cross_connect 1")
+    dev[0].global_request("P2P_SET cross_connect 1")
     dev[0].p2p_start_go(no_event_clear=True)
     ev = dev[0].wait_global_event("P2P-CROSS-CONNECT-ENABLE", timeout=10)
     if ev is None:
@@ -76,7 +76,7 @@
     ev = dev[0].wait_global_event("P2P-CROSS-CONNECT-DISABLE", timeout=10)
     if ev is None:
         raise Exception("Timeout on cross connection disabled event")
-    dev[0].request("P2P_SET cross_connect 0")
+    dev[0].global_request("P2P_SET cross_connect 0")
 
 def test_concurrent_p2pcli(dev, apdev):
     """Concurrent P2P client join"""
@@ -193,7 +193,7 @@
     """Concurrent P2P persistent group"""
     logger.info("Connect to an infrastructure AP")
     hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open", "channel": "2" })
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2417")
 
     logger.info("Run persistent group test while associated to an AP")
@@ -213,7 +213,7 @@
 
     logger.info("Connect to an infrastructure AP")
     hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open", "channel": "2" })
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2417")
     invite(dev[1], dev[0], extra="freq=2412")
     ev = dev[1].wait_global_event(["P2P-INVITATION-RESULT"], timeout=15)
diff --git a/tests/hwsim/test_p2p_device.py b/tests/hwsim/test_p2p_device.py
index cfea9b3..a36eb38 100644
--- a/tests/hwsim/test_p2p_device.py
+++ b/tests/hwsim/test_p2p_device.py
@@ -1,5 +1,5 @@
 # cfg80211 P2P Device
-# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -12,7 +12,10 @@
 from test_p2p_grpform import go_neg_pin_authorized
 from test_p2p_grpform import check_grpform_results
 from test_p2p_grpform import remove_group
+from test_nfc_p2p import set_ip_addr_info, check_ip_addr, grpform_events
 from hwsim import HWSimRadio
+import hostapd
+import hwsim_utils
 
 def test_p2p_device_grpform(dev, apdev):
     """P2P group formation with driver using cfg80211 P2P Device"""
@@ -78,3 +81,147 @@
         ev = wpas.wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15)
         if ev is None:
             raise Exception("Station mode scan did not start")
+
+def test_p2p_device_nfc_invite(dev, apdev):
+    """P2P NFC invitiation with driver using cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        set_ip_addr_info(dev[0])
+        logger.info("Start autonomous GO")
+        dev[0].p2p_start_go()
+
+        logger.info("Write NFC Tag on the P2P Client")
+        res = wpas.global_request("P2P_LISTEN")
+        if "FAIL" in res:
+            raise Exception("Failed to start Listen mode")
+        pw = wpas.global_request("WPS_NFC_TOKEN NDEF").rstrip()
+        if "FAIL" in pw:
+            raise Exception("Failed to generate password token")
+        res = wpas.global_request("P2P_SET nfc_tag 1").rstrip()
+        if "FAIL" in res:
+            raise Exception("Failed to enable NFC Tag for P2P static handover")
+        sel = wpas.global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+        if "FAIL" in sel:
+            raise Exception("Failed to generate NFC connection handover select")
+
+        logger.info("Read NFC Tag on the GO to trigger invitation")
+        res = dev[0].request("WPS_NFC_TAG_READ " + sel)
+        if "FAIL" in res:
+            raise Exception("Failed to provide NFC tag contents to wpa_supplicant")
+
+        ev = wpas.wait_global_event(grpform_events, timeout=20)
+        if ev is None:
+            raise Exception("Joining the group timed out")
+        res = wpas.group_form_result(ev)
+        hwsim_utils.test_connectivity_p2p(dev[0], wpas)
+        check_ip_addr(res)
+
+def test_p2p_device_misuses(dev, apdev):
+    """cfg80211 P2P Device misuses"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        # Add a normal network profile to the P2P Device management only
+        # interface to verify that it does not get used.
+        id = int(wpas.global_request('IFNAME=p2p-dev-%s ADD_NETWORK' % iface).strip())
+        wpas.global_request('IFNAME=p2p-dev-%s SET_NETWORK %d ssid "open"' % (iface, id))
+        wpas.global_request('IFNAME=p2p-dev-%s SET_NETWORK %d key_mgmt NONE' % (iface, id))
+        wpas.global_request('IFNAME=p2p-dev-%s ENABLE_NETWORK %d' % (iface, id))
+
+        # Scan requests get ignored on p2p-dev
+        wpas.global_request('IFNAME=p2p-dev-%s SCAN' % iface)
+
+        dev[0].p2p_start_go(freq=2412)
+        addr = dev[0].p2p_interface_addr()
+        wpas.scan_for_bss(addr, freq=2412)
+        wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+        hwsim_utils.test_connectivity(wpas, hapd)
+
+        pin = wpas.wps_read_pin()
+        dev[0].p2p_go_authorize_client(pin)
+        res = wpas.p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60,
+                                     social=True, freq=2412)
+        hwsim_utils.test_connectivity_p2p(dev[0], wpas)
+
+        # Optimize scan-after-disconnect
+        wpas.group_request("SET_NETWORK 0 scan_freq 2412")
+
+        dev[0].request("DISASSOCIATE " + wpas.p2p_interface_addr())
+        ev = wpas.wait_group_event(["CTRL-EVENT-DISCONNECT"])
+        if ev is None:
+            raise Exception("Did not see disconnect event on P2P group interface")
+        dev[0].remove_group()
+
+        ev = wpas.wait_group_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("Scan not started")
+        ev = wpas.wait_group_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=15)
+        if ev is None:
+            raise Exception("Scan not completed")
+        time.sleep(1)
+        hwsim_utils.test_connectivity(wpas, hapd)
+
+        ev = hapd.wait_event([ "AP-STA-DISCONNECTED" ], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected disconnection event received from hostapd")
+        ev = wpas.wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected disconnection event received from wpa_supplicant")
+
+        wpas.request("DISCONNECT")
+        wpas.wait_disconnected()
+
+def test_p2p_device_incorrect_command_interface(dev, apdev):
+    """cfg80211 P2P Device and P2P_* command on incorrect interface"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        dev[0].p2p_listen()
+        wpas.request('P2P_FIND type=social')
+        ev = wpas.wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+        if ev is None:
+            raise Exception("Peer not found")
+        ev = wpas.wait_event(["P2P-DEVICE-FOUND"], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected P2P-DEVICE-FOUND event on station interface")
+
+        pin = wpas.wps_read_pin()
+        dev[0].p2p_go_neg_auth(wpas.p2p_dev_addr(), pin, "enter", go_intent=14,
+                               freq=2412)
+        wpas.request('P2P_STOP_FIND')
+        if "OK" not in wpas.request('P2P_CONNECT ' + dev[0].p2p_dev_addr() + ' ' + pin + ' display go_intent=1'):
+            raise Exception("P2P_CONNECT failed")
+
+        ev = wpas.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+        if ev is None:
+            raise Exception("Group formation timed out")
+        wpas.group_form_result(ev)
+
+        ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+        if ev is None:
+            raise Exception("Group formation timed out(2)")
+        dev[0].group_form_result(ev)
+
+        dev[0].remove_group()
+        wpas.wait_go_ending_session()
+
+def test_p2p_device_incorrect_command_interface2(dev, apdev):
+    """cfg80211 P2P Device and P2P_GROUP_ADD command on incorrect interface"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        print wpas.request('P2P_GROUP_ADD')
+        ev = wpas.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+        if ev is None:
+            raise Exception("Group formation timed out")
+        res = wpas.group_form_result(ev)
+        logger.info("Group results: " + str(res))
+        wpas.remove_group()
+        if not res['ifname'].startswith('p2p-' + iface + '-'):
+            raise Exception("Unexpected group ifname: " + res['ifname'])
diff --git a/tests/hwsim/test_p2p_discovery.py b/tests/hwsim/test_p2p_discovery.py
index 9b97d39..6f7aefa 100644
--- a/tests/hwsim/test_p2p_discovery.py
+++ b/tests/hwsim/test_p2p_discovery.py
@@ -86,6 +86,8 @@
         raise Exception("Invalid P2P_PROV_DISC accepted")
     if "FAIL" not in dev[0].global_request("P2P_PROV_DISC 00:11:22:33:44:55 pbc join"):
         raise Exception("Invalid P2P_PROV_DISC accepted")
+    if "FAIL" not in dev[0].global_request("P2P_PROV_DISC 00:11:22:33:44:55 foo"):
+        raise Exception("Invalid P2P_PROV_DISC accepted")
 
 def test_discovery_pd_retries(dev):
     """P2P device discovery and provision discovery retries"""
@@ -97,7 +99,7 @@
     dev[1].p2p_stop_find()
     dev[0].p2p_stop_find()
     dev[0].global_request("P2P_PROV_DISC " + addr1 + " display")
-    ev = dev[0].wait_event(["P2P-PROV-DISC-FAILURE"], timeout=60)
+    ev = dev[0].wait_global_event(["P2P-PROV-DISC-FAILURE"], timeout=60)
     if ev is None:
         raise Exception("No PD failure reported")
 
@@ -130,19 +132,22 @@
     # make group client non-responsive on operating channel
     dev[1].dump_monitor()
     dev[1].group_request("DISCONNECT")
-    dev[1].wait_disconnected(timeout=10)
+    ev = dev[1].wait_group_event(["CTRL-EVENT-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("Timeout on waiting disconnection")
     dev[2].request("P2P_CONNECT {} {} display".format(dev[1].p2p_dev_addr(),
                                                       pin))
-    ev = dev[1].wait_event(["P2P-GO-NEG-REQUEST"], timeout=2)
+    ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=2)
     if ev:
         raise Exception("Unexpected frame RX on P2P client")
     # make group client available on operating channe
-    dev[1].request("REASSOCIATE")
-    ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED", "P2P-GO-NEG-REQUEST"])
+    dev[1].group_request("REASSOCIATE")
+    ev = dev[1].wait_global_event(["CTRL-EVENT-CONNECTED",
+                                   "P2P-GO-NEG-REQUEST"], timeout=10)
     if ev is None:
         raise Exception("Timeout on reconnection to group")
     if "P2P-GO-NEG-REQUEST" not in ev:
-        ev = dev[1].wait_event(["P2P-GO-NEG-REQUEST"])
+        ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
         if ev is None:
             raise Exception("Timeout on waiting for GO Negotiation Request")
 
@@ -151,11 +156,11 @@
     dev[1].request("SET sec_device_type 1-0050F204-2")
     dev[1].p2p_listen()
     dev[0].p2p_find(social=True, dev_type="5-0050F204-1")
-    ev = dev[0].wait_event(['P2P-DEVICE-FOUND'], timeout=1)
+    ev = dev[0].wait_global_event(['P2P-DEVICE-FOUND'], timeout=1)
     if ev:
         raise Exception("Unexpected P2P device found")
     dev[0].p2p_find(social=True, dev_type="1-0050F204-2")
-    ev = dev[0].wait_event(['P2P-DEVICE-FOUND'], timeout=2)
+    ev = dev[0].wait_global_event(['P2P-DEVICE-FOUND'], timeout=2)
     if ev is None:
         raise Exception("P2P device not found")
     peer = dev[0].get_peer(dev[1].p2p_dev_addr())
@@ -172,11 +177,11 @@
     dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
 
     dev[2].p2p_find(social=True, dev_type="5-0050F204-1")
-    ev = dev[2].wait_event(['P2P-DEVICE-FOUND'], timeout=1)
+    ev = dev[2].wait_global_event(['P2P-DEVICE-FOUND'], timeout=1)
     if ev:
         raise Exception("Unexpected P2P device found")
     dev[2].p2p_find(social=True, dev_type="1-0050F204-2")
-    ev = dev[2].wait_event(['P2P-DEVICE-FOUND ' + addr1], timeout=2)
+    ev = dev[2].wait_global_event(['P2P-DEVICE-FOUND ' + addr1], timeout=2)
     if ev is None:
         raise Exception("P2P device not found")
 
@@ -191,11 +196,11 @@
     addr1 = dev[1].p2p_dev_addr()
     dev[1].p2p_listen()
     dev[0].p2p_find(social=True, dev_id="02:03:04:05:06:07")
-    ev = dev[0].wait_event(['P2P-DEVICE-FOUND'], timeout=1)
+    ev = dev[0].wait_global_event(['P2P-DEVICE-FOUND'], timeout=1)
     if ev:
         raise Exception("Unexpected P2P device found")
     dev[0].p2p_find(social=True, dev_id=addr1)
-    ev = dev[0].wait_event(['P2P-DEVICE-FOUND'], timeout=2)
+    ev = dev[0].wait_global_event(['P2P-DEVICE-FOUND'], timeout=5)
     if ev is None:
         raise Exception("P2P device not found")
     if addr1 not in ev:
@@ -218,11 +223,11 @@
     dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
 
     dev[2].p2p_find(social=True, dev_id="02:03:04:05:06:07")
-    ev = dev[2].wait_event(['P2P-DEVICE-FOUND'], timeout=1)
+    ev = dev[2].wait_global_event(['P2P-DEVICE-FOUND'], timeout=1)
     if ev:
         raise Exception("Unexpected P2P device found")
     dev[2].p2p_find(social=True, dev_id=addr1)
-    ev = dev[2].wait_event(['P2P-DEVICE-FOUND ' + addr1], timeout=2)
+    ev = dev[2].wait_global_event(['P2P-DEVICE-FOUND ' + addr1], timeout=2)
     if ev is None:
         raise Exception("P2P device not found")
 
@@ -361,7 +366,7 @@
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.5)
     if ev is None:
         logger.info("No CTRL-EVENT-SCAN-STARTED event")
-    dev[0].request("P2P_FLUSH")
+    dev[0].global_request("P2P_FLUSH")
     ev = dev[0].wait_global_event(["P2P-FIND-STOPPED"], timeout=1)
     if ev is None:
         raise Exception("P2P_STOP not reported")
@@ -412,7 +417,7 @@
 
     dev[0].p2p_listen()
     dev[0].global_request("P2P_PROV_DISC " + addr1 + " display")
-    ev = dev[0].wait_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=15)
+    ev = dev[0].wait_global_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=15)
     if ev is None:
         raise Exception("No PD result reported")
     dev[1].p2p_stop_find()
diff --git a/tests/hwsim/test_p2p_grpform.py b/tests/hwsim/test_p2p_grpform.py
index 1528142..513d438 100644
--- a/tests/hwsim/test_p2p_grpform.py
+++ b/tests/hwsim/test_p2p_grpform.py
@@ -14,6 +14,7 @@
 import hostapd
 import hwsim_utils
 import utils
+from utils import HwsimSkip
 from wpasupplicant import WpaSupplicant
 
 def check_grpform_results(i_res, r_res):
@@ -142,6 +143,26 @@
     i_dev.dump_monitor()
     return [i_res, r_res]
 
+def go_neg_pbc_authorized(i_dev, r_dev, i_intent=None, r_intent=None,
+                          expect_failure=False, i_freq=None, r_freq=None):
+    i_dev.p2p_listen()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), None, "pbc",
+                          go_intent=r_intent, freq=r_freq)
+    r_dev.p2p_listen()
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=20,
+                                  go_intent=i_intent,
+                                  expect_failure=expect_failure, freq=i_freq)
+    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    i_dev.dump_monitor()
+    if expect_failure:
+        return
+    logger.info("Group formed")
+    return [i_res, r_res]
+
 def remove_group(dev1, dev2):
     dev1.remove_group()
     try:
@@ -152,7 +173,7 @@
 def test_grpform(dev):
     """P2P group formation using PIN and authorized connection (init -> GO)"""
     try:
-        dev[0].request("SET p2p_group_idle 2")
+        dev[0].global_request("SET p2p_group_idle 2")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0)
         check_grpform_results(i_res, r_res)
@@ -163,11 +184,11 @@
         if "GO reason=IDLE" not in ev:
             raise Exception("Unexpected group removal event: " + ev)
     finally:
-        dev[0].request("SET p2p_group_idle 0")
+        dev[0].global_request("SET p2p_group_idle 0")
 
 def test_grpform_a(dev):
     """P2P group formation using PIN and authorized connection (init -> GO) (init: group iface)"""
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                            r_dev=dev[1], r_intent=0)
     if "p2p-wlan" not in i_res['ifname']:
@@ -179,7 +200,7 @@
 
 def test_grpform_b(dev):
     """P2P group formation using PIN and authorized connection (init -> GO) (resp: group iface)"""
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                            r_dev=dev[1], r_intent=0)
     if "p2p-wlan" not in r_res['ifname']:
@@ -191,8 +212,8 @@
 
 def test_grpform_c(dev):
     """P2P group formation using PIN and authorized connection (init -> GO) (group iface)"""
-    dev[0].request("SET p2p_no_group_iface 0")
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                            r_dev=dev[1], r_intent=0)
     if "p2p-wlan" not in i_res['ifname']:
@@ -213,8 +234,8 @@
 
 def test_grpform2_c(dev):
     """P2P group formation using PIN and authorized connection (resp -> GO) (group iface)"""
-    dev[0].request("SET p2p_no_group_iface 0")
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0, r_dev=dev[1], r_intent=15)
     remove_group(dev[0], dev[1])
     if i_res['ifname'] in utils.get_ifnames():
@@ -229,8 +250,8 @@
 
 def test_grpform3_c(dev):
     """P2P group formation using PIN and re-init GO Negotiation (group iface)"""
-    dev[0].request("SET p2p_no_group_iface 0")
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     [i_res, r_res] = go_neg_pin(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
     remove_group(dev[0], dev[1])
     if i_res['ifname'] in utils.get_ifnames():
@@ -254,14 +275,17 @@
 
 def test_grpform_ext_listen(dev):
     """P2P group formation with extended listen timing enabled"""
+    addr0 = dev[0].p2p_dev_addr()
     try:
         if "FAIL" not in dev[0].global_request("P2P_EXT_LISTEN 100"):
             raise Exception("Invalid P2P_EXT_LISTEN accepted")
-        if "OK" not in dev[0].global_request("P2P_EXT_LISTEN 100 50000"):
+        if "OK" not in dev[0].global_request("P2P_EXT_LISTEN 300 1000"):
             raise Exception("Failed to set extended listen timing")
         if "OK" not in dev[1].global_request("P2P_EXT_LISTEN 200 40000"):
             raise Exception("Failed to set extended listen timing")
-        [i_res, r_res] = go_neg_pbc(i_dev=dev[0], provdisc=True, r_dev=dev[1], r_listen=True)
+        [i_res, r_res] = go_neg_pbc(i_dev=dev[0], provdisc=True, r_dev=dev[1],
+                                    r_listen=True, i_freq="2417", r_freq="2417",
+                                    i_intent=1, r_intent=15)
         check_grpform_results(i_res, r_res)
         peer1 = dev[0].get_peer(dev[1].p2p_dev_addr())
         if peer1['ext_listen_interval'] != "40000":
@@ -269,10 +293,12 @@
         if peer1['ext_listen_period'] != "200":
             raise Exception("Extended listen period not discovered correctly")
         peer0 = dev[1].get_peer(dev[0].p2p_dev_addr())
-        if peer0['ext_listen_interval'] != "50000":
+        if peer0['ext_listen_interval'] != "1000":
             raise Exception("Extended listen interval not discovered correctly")
-        if peer0['ext_listen_period'] != "100":
+        if peer0['ext_listen_period'] != "300":
             raise Exception("Extended listen period not discovered correctly")
+        if not dev[2].discover_peer(addr0):
+            raise Exception("Could not discover peer during ext listen")
         remove_group(dev[0], dev[1])
     finally:
         if "OK" not in dev[0].global_request("P2P_EXT_LISTEN"):
@@ -334,7 +360,7 @@
 
 def test_grpform_per_sta_psk(dev):
     """P2P group formation with per-STA PSKs"""
-    dev[0].request("P2P_SET per_sta_psk 1")
+    dev[0].global_request("P2P_SET per_sta_psk 1")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
     check_grpform_results(i_res, r_res)
 
@@ -354,7 +380,7 @@
 
 def test_grpform_per_sta_psk_wps(dev):
     """P2P group formation with per-STA PSKs with non-P2P WPS STA"""
-    dev[0].request("P2P_SET per_sta_psk 1")
+    dev[0].global_request("P2P_SET per_sta_psk 1")
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
     check_grpform_results(i_res, r_res)
 
@@ -501,31 +527,31 @@
     addr1 = dev[1].p2p_dev_addr()
     if not dev[0].discover_peer(addr1):
         raise Exception("Peer not found")
-    res = dev[1].request("P2P_CONNECT " + dev[0].p2p_dev_addr() + " pin auth go_intent=0")
+    res = dev[1].global_request("P2P_CONNECT " + dev[0].p2p_dev_addr() + " pin auth go_intent=0")
     if "FAIL" in res:
         raise Exception("P2P_CONNECT failed to generate PIN")
     logger.info("PIN from P2P_CONNECT: " + res)
-    dev[0].request("P2P_CONNECT " + addr1 + " 00000000 enter go_intent=15")
+    dev[0].global_request("P2P_CONNECT " + addr1 + " 00000000 enter go_intent=15")
     ev = dev[0].wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=15)
     if ev is None:
         raise Exception("GO Negotiation did not complete successfully(0)")
     ev = dev[1].wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=15)
     if ev is None:
         raise Exception("GO Negotiation did not complete successfully(1)")
-    ev = dev[1].wait_event(["WPS-FAIL"], timeout=15)
+    ev = dev[1].wait_global_event(["WPS-FAIL"], timeout=15)
     if ev is None:
         raise Exception("WPS failure not reported(1)")
     if "msg=8 config_error=18" not in ev:
         raise Exception("Unexpected WPS failure(1): " + ev)
-    ev = dev[0].wait_event(["WPS-FAIL"], timeout=15)
+    ev = dev[0].wait_global_event(["WPS-FAIL"], timeout=15)
     if ev is None:
         raise Exception("WPS failure not reported")
     if "msg=8 config_error=18" not in ev:
         raise Exception("Unexpected WPS failure: " + ev)
-    ev = dev[1].wait_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=10)
+    ev = dev[1].wait_global_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=10)
     if ev is None:
         raise Exception("Group formation failure timed out")
-    ev = dev[0].wait_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=5)
+    ev = dev[0].wait_global_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=5)
     if ev is None:
         raise Exception("Group formation failure timed out")
 
@@ -576,7 +602,7 @@
         raise Exception("Peer listen frequency learned unexpectedly from PD Request")
 
     pin = dev[0].wps_read_pin()
-    if "FAIL" in dev[1].request("P2P_CONNECT " + addr0 + " " + pin + " enter"):
+    if "FAIL" in dev[1].global_request("P2P_CONNECT " + addr0 + " " + pin + " enter"):
         raise Exception("P2P_CONNECT on initiator failed")
     ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=5)
     if ev is None:
@@ -584,7 +610,7 @@
     peer = dev[0].get_peer(addr1)
     if peer['listen_freq'] == '0':
         raise Exception("Peer listen frequency not learned from PD followed by GO Neg Req")
-    if "FAIL" in dev[0].request("P2P_CONNECT " + addr1 + " " + pin + " display"):
+    if "FAIL" in dev[0].global_request("P2P_CONNECT " + addr1 + " " + pin + " display"):
         raise Exception("P2P_CONNECT on responder failed")
     ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
@@ -662,9 +688,9 @@
     if not dev[0].discover_peer(addr1):
         raise Exception("Could not discover peer")
     dev[0].p2p_listen()
-    if "OK" not in dev[0].request("P2P_CONNECT " + addr1 + " pbc auth go_intent=0"):
+    if "OK" not in dev[0].global_request("P2P_CONNECT " + addr1 + " pbc auth go_intent=0"):
         raise Exception("Failed to authorize GO Neg")
-    if "OK" not in dev[1].request("P2P_CONNECT " + addr0 + " pbc go_intent=15 freq=2412"):
+    if "OK" not in dev[1].global_request("P2P_CONNECT " + addr0 + " pbc go_intent=15 freq=2412"):
         raise Exception("Failed to initiate GO Neg")
     ev = dev[0].wait_global_event(["WPS-OVERLAP-DETECTED"], timeout=15)
     if ev is None:
@@ -695,9 +721,9 @@
     dev[0].p2p_stop_find()
     dev[0].scan(freq="2412")
     dev[0].p2p_listen()
-    if "OK" not in dev[0].request("P2P_CONNECT " + addr1 + " pbc auth go_intent=0"):
+    if "OK" not in dev[0].global_request("P2P_CONNECT " + addr1 + " pbc auth go_intent=0"):
         raise Exception("Failed to authorize GO Neg")
-    if "OK" not in dev[1].request("P2P_CONNECT " + addr0 + " pbc go_intent=15 freq=2412"):
+    if "OK" not in dev[1].global_request("P2P_CONNECT " + addr0 + " pbc go_intent=15 freq=2412"):
         raise Exception("Failed to initiate GO Neg")
     ev = dev[0].wait_global_event(["WPS-OVERLAP-DETECTED",
                                    "P2P-GROUP-FORMATION-SUCCESS"], timeout=15)
@@ -728,8 +754,7 @@
 def test_grpform_cred_ready_timeout(dev, apdev, params):
     """P2P GO Negotiation wait for credentials to become ready [long]"""
     if not params['long']:
-        logger.info("Skip test case with long duration due to --long not specified")
-        return "skip"
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
 
     dev[1].p2p_listen()
     addr1 = dev[1].p2p_dev_addr()
@@ -831,6 +856,7 @@
         if ev is None:
             raise Exception("Group formation timed out on P2P Client")
         dev[0].remove_group()
+        dev[1].wait_go_ending_session()
 
         if mode != "P2P GO - group formation":
             raise Exception("Unexpected mode on GO during group formation: " + mode)
@@ -896,3 +922,55 @@
     ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
     if ev is None:
         raise Exception("No GO Negotiation Request RX reported")
+
+def test_grpform_pbc_multiple(dev):
+    """P2P group formation using PBC multiple times in a row"""
+    try:
+        dev[1].request("SET passive_scan 1")
+        for i in range(5):
+            [i_res, r_res] = go_neg_pbc_authorized(i_dev=dev[0], i_intent=15,
+                                                   r_dev=dev[1], r_intent=0)
+            remove_group(dev[0], dev[1])
+    finally:
+        dev[1].request("SET passive_scan 0")
+        dev[1].flush_scan_cache()
+
+def test_grpform_not_ready(dev):
+    """Not ready for GO Negotiation (listen)"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr2 = dev[2].p2p_dev_addr()
+    dev[0].p2p_listen()
+    if not dev[1].discover_peer(addr0):
+        raise Exception("Could not discover peer")
+    dev[1].global_request("P2P_CONNECT " + addr0 + " pbc")
+    ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=5)
+    if ev is None:
+        raise Exception("No P2P-GO-NEG-REQUEST event")
+    dev[0].dump_monitor()
+    time.sleep(5)
+    if not dev[2].discover_peer(addr0):
+        raise Exception("Could not discover peer(2)")
+    for i in range(3):
+        dev[i].p2p_stop_find()
+
+def test_grpform_not_ready2(dev):
+    """Not ready for GO Negotiation (search)"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr2 = dev[2].p2p_dev_addr()
+    dev[0].p2p_find(social=True)
+    if not dev[1].discover_peer(addr0):
+        raise Exception("Could not discover peer")
+    dev[1].global_request("P2P_CONNECT " + addr0 + " pbc")
+    ev = dev[0].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=5)
+    if ev is None:
+        raise Exception("No P2P-GO-NEG-REQUEST event")
+    dev[0].dump_monitor()
+    time.sleep(1)
+    dev[2].p2p_listen()
+    ev = dev[0].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("Peer not discovered after GO Neg Resp(status=1) TX")
+    if addr2 not in ev:
+        raise Exception("Unexpected peer discovered: " + ev)
+    for i in range(3):
+        dev[i].p2p_stop_find()
diff --git a/tests/hwsim/test_p2p_invitation.py b/tests/hwsim/test_p2p_invitation.py
index bc4fb1b..ffe8437 100644
--- a/tests/hwsim/test_p2p_invitation.py
+++ b/tests/hwsim/test_p2p_invitation.py
@@ -94,6 +94,7 @@
         raise Exception("Timeout on invitation on peer")
     if "P2P-INVITATION-RECEIVED" in ev:
         raise Exception("Unexpected request to accept pre-authorized invitaton")
+    dev[1].group_form_result(ev)
     dev[0].dump_monitor()
 
     logger.info("Client connected")
diff --git a/tests/hwsim/test_p2p_messages.py b/tests/hwsim/test_p2p_messages.py
index 334d28b..b7ced2b 100644
--- a/tests/hwsim/test_p2p_messages.py
+++ b/tests/hwsim/test_p2p_messages.py
@@ -279,6 +279,44 @@
     msg = p2p_hdr(dst, src)
     hapd.mgmt_tx(msg)
 
+def test_p2p_msg_long_ssid(dev, apdev):
+    """P2P protocol test: Too long SSID in P2P Public Action frame"""
+    dst, src, hapd, channel = start_p2p(dev, apdev)
+
+    msg = p2p_hdr(dst, src, type=P2P_INVITATION_REQ, dialog_token=1)
+    attrs = p2p_attr_config_timeout()
+    attrs += p2p_attr_invitation_flags()
+    attrs += p2p_attr_operating_channel()
+    attrs += p2p_attr_group_bssid(src)
+    attrs += p2p_attr_channel_list()
+    attrs += p2p_attr_group_id(src, 'DIRECT-foo')
+    attrs += p2p_attr_device_info(src, config_methods=0x0108)
+    msg['payload'] += ie_p2p(attrs)
+    msg['payload'] += ie_ssid(255 * 'A')
+    hapd.mgmt_tx(msg)
+    ev = dev[0].wait_event(["P2P-DEVICE-FOUND"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on device found event")
+
+def test_p2p_msg_long_dev_name(dev, apdev):
+    """P2P protocol test: Too long Device Name in P2P Public Action frame"""
+    dst, src, hapd, channel = start_p2p(dev, apdev)
+
+    msg = p2p_hdr(dst, src, type=P2P_INVITATION_REQ, dialog_token=1)
+    attrs = p2p_attr_config_timeout()
+    attrs += p2p_attr_invitation_flags()
+    attrs += p2p_attr_operating_channel()
+    attrs += p2p_attr_group_bssid(src)
+    attrs += p2p_attr_channel_list()
+    attrs += p2p_attr_group_id(src, 'DIRECT-foo')
+    attrs += p2p_attr_device_info(src, config_methods=0x0108,
+                                  name="123456789012345678901234567890123")
+    msg['payload'] += ie_p2p(attrs)
+    hapd.mgmt_tx(msg)
+    ev = dev[0].wait_event(["P2P-DEVICE-FOUND"], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected device found event")
+
 def test_p2p_msg_invitation_req(dev, apdev):
     """P2P protocol tests for invitation request processing"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
diff --git a/tests/hwsim/test_p2p_service.py b/tests/hwsim/test_p2p_service.py
index 028e06b..ea7a8f4 100644
--- a/tests/hwsim/test_p2p_service.py
+++ b/tests/hwsim/test_p2p_service.py
@@ -6,26 +6,27 @@
 
 import logging
 logger = logging.getLogger()
+import time
 import uuid
 
 import hwsim_utils
 
 def add_bonjour_services(dev):
-    dev.request("P2P_SERVICE_ADD bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027")
-    dev.request("P2P_SERVICE_ADD bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00")
-    dev.request("P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027")
-    dev.request("P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074")
+    dev.global_request("P2P_SERVICE_ADD bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027")
+    dev.global_request("P2P_SERVICE_ADD bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00")
+    dev.global_request("P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027")
+    dev.global_request("P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074")
 
 def add_upnp_services(dev):
-    dev.request("P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice")
-    dev.request("P2P_SERVICE_ADD upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice")
-    dev.request("P2P_SERVICE_ADD upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2")
-    dev.request("P2P_SERVICE_ADD upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2")
-    dev.request("P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1")
+    dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice")
+    dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice")
+    dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2")
+    dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2")
+    dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1")
 
 def add_extra_services(dev):
     for i in range(0, 100):
-        dev.request("P2P_SERVICE_ADD upnp 10 uuid:" + str(uuid.uuid4()) + "::upnp:rootdevice")
+        dev.global_request("P2P_SERVICE_ADD upnp 10 uuid:" + str(uuid.uuid4()) + "::upnp:rootdevice")
 
 def run_sd(dev, dst, query, exp_query=None, fragment=False, query2=None):
     addr0 = dev[0].p2p_dev_addr()
@@ -36,14 +37,14 @@
         add_extra_services(dev[0])
     dev[0].p2p_listen()
 
-    dev[1].request("P2P_FLUSH")
-    dev[1].request("P2P_SERV_DISC_REQ " + dst + " " + query)
+    dev[1].global_request("P2P_FLUSH")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + dst + " " + query)
     if query2:
-        dev[1].request("P2P_SERV_DISC_REQ " + dst + " " + query2)
+        dev[1].global_request("P2P_SERV_DISC_REQ " + dst + " " + query2)
     if not dev[1].discover_peer(addr0, social=True, force_find=True):
         raise Exception("Peer " + addr0 + " not found")
 
-    ev = dev[0].wait_event(["P2P-SERV-DISC-REQ"], timeout=10)
+    ev = dev[0].wait_global_event(["P2P-SERV-DISC-REQ"], timeout=10)
     if ev is None:
         raise Exception("Service discovery timed out")
     if addr1 not in ev:
@@ -56,7 +57,7 @@
     if query2:
         ev_list = []
         for i in range(0, 4):
-            ev = dev[1].wait_event(["P2P-SERV-DISC-RESP"], timeout=10)
+            ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=10)
             if ev is None:
                 raise Exception("Service discovery timed out")
             if addr0 in ev:
@@ -66,7 +67,7 @@
         return ev_list
 
     for i in range(0, 2):
-        ev = dev[1].wait_event(["P2P-SERV-DISC-RESP"], timeout=10)
+        ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=10)
         if ev is None:
             raise Exception("Service discovery timed out")
         if addr0 in ev:
@@ -75,13 +76,13 @@
     dev[0].p2p_stop_find()
     dev[1].p2p_stop_find()
 
-    if "OK" not in dev[0].request("P2P_SERVICE_DEL upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice"):
+    if "OK" not in dev[0].global_request("P2P_SERVICE_DEL upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice"):
         raise Exception("Failed to delete a UPnP service")
-    if "FAIL" not in dev[0].request("P2P_SERVICE_DEL upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice"):
+    if "FAIL" not in dev[0].global_request("P2P_SERVICE_DEL upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice"):
         raise Exception("Unexpected deletion success for UPnP service")
-    if "OK" not in dev[0].request("P2P_SERVICE_DEL bonjour 0b5f6166706f766572746370c00c000c01"):
+    if "OK" not in dev[0].global_request("P2P_SERVICE_DEL bonjour 0b5f6166706f766572746370c00c000c01"):
         raise Exception("Failed to delete a Bonjour service")
-    if "FAIL" not in dev[0].request("P2P_SERVICE_DEL bonjour 0b5f6166706f766572746370c00c000c01"):
+    if "FAIL" not in dev[0].global_request("P2P_SERVICE_DEL bonjour 0b5f6166706f766572746370c00c000c01"):
         raise Exception("Unexpected deletion success for Bonjour service")
 
     return ev
@@ -102,7 +103,7 @@
                  addr0 + " upnp 10",
                  addr0 + " 123",
                  addr0 + " qq" ]:
-        if "FAIL" not in dev[1].request("P2P_SERV_DISC_REQ " + req):
+        if "FAIL" not in dev[1].global_request("P2P_SERV_DISC_REQ " + req):
             raise Exception("Invalid P2P_SERV_DISC_REQ accepted: " + req)
 
 def test_p2p_service_discovery2(dev):
@@ -230,36 +231,36 @@
 
 def test_p2p_service_discovery_wfd(dev):
     """P2P service discovery (Wi-Fi Display)"""
-    dev[0].request("SET wifi_display 1")
+    dev[0].global_request("SET wifi_display 1")
     ev = run_sd(dev, "00:00:00:00:00:00", "02000401")
     if " 030004" in ev:
         raise Exception("Unexpected response to invalid WFD SD query")
-    dev[0].request("SET wifi_display 0")
+    dev[0].global_request("SET wifi_display 0")
     ev = run_sd(dev, "00:00:00:00:00:00", "0300040100")
     if "0300040101" not in ev:
         raise Exception("Unexpected response to WFD SD query (protocol was disabled)")
 
 def test_p2p_service_discovery_req_cancel(dev):
     """Cancel a P2P service discovery request"""
-    if "FAIL" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ ab"):
+    if "FAIL" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ ab"):
         raise Exception("Unexpected SD cancel success")
-    if "FAIL" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ qq"):
+    if "FAIL" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ qq"):
         raise Exception("Unexpected SD cancel success")
-    query = dev[0].request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000001")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ " + query):
+    query = dev[0].global_request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000001")
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query):
         raise Exception("Unexpected SD cancel failure")
-    query1 = dev[0].request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000001")
-    query2 = dev[0].request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000002")
-    query3 = dev[0].request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000003")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ " + query2):
+    query1 = dev[0].global_request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000001")
+    query2 = dev[0].global_request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000002")
+    query3 = dev[0].global_request("P2P_SERV_DISC_REQ " + dev[1].p2p_dev_addr() + " 02000003")
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query2):
         raise Exception("Unexpected SD cancel failure")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ " + query1):
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query1):
         raise Exception("Unexpected SD cancel failure")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ " + query3):
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query3):
         raise Exception("Unexpected SD cancel failure")
 
-    query = dev[0].request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000001")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_CANCEL_REQ " + query):
+    query = dev[0].global_request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000001")
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query):
         raise Exception("Unexpected SD(broadcast) cancel failure")
 
 def test_p2p_service_discovery_go(dev):
@@ -272,18 +273,18 @@
 
     dev[0].p2p_start_go(freq=2412)
 
-    dev[1].request("P2P_FLUSH")
-    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    dev[1].global_request("P2P_FLUSH")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
     if not dev[1].discover_peer(addr0, social=True, force_find=True):
         raise Exception("Peer " + addr0 + " not found")
 
-    ev = dev[0].wait_event(["P2P-SERV-DISC-REQ"], timeout=10)
+    ev = dev[0].wait_global_event(["P2P-SERV-DISC-REQ"], timeout=10)
     if ev is None:
         raise Exception("Service discovery timed out")
     if addr1 not in ev:
         raise Exception("Unexpected service discovery request source")
 
-    ev = dev[1].wait_event(["P2P-SERV-DISC-RESP"], timeout=10)
+    ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=10)
     if ev is None:
         raise Exception("Service discovery timed out")
     if addr0 not in ev:
@@ -294,19 +295,19 @@
         raise Exception("Unexpected service discovery response contents (UPnP)")
     dev[1].p2p_stop_find()
 
-    dev[0].request("P2P_SERVICE_FLUSH")
+    dev[0].global_request("P2P_SERVICE_FLUSH")
 
-    dev[1].request("P2P_FLUSH")
-    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    dev[1].global_request("P2P_FLUSH")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
     if not dev[1].discover_peer(addr0, social=True, force_find=True):
         raise Exception("Peer " + addr0 + " not found")
-    ev = dev[0].wait_event(["P2P-SERV-DISC-REQ"], timeout=10)
+    ev = dev[0].wait_global_event(["P2P-SERV-DISC-REQ"], timeout=10)
     if ev is None:
         raise Exception("Service discovery timed out")
     if addr1 not in ev:
         raise Exception("Unexpected service discovery request source")
 
-    ev = dev[1].wait_event(["P2P-SERV-DISC-RESP"], timeout=10)
+    ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=10)
     if ev is None:
         raise Exception("Service discovery timed out")
     if addr0 not in ev:
@@ -319,13 +320,13 @@
     addr0 = dev[0].p2p_dev_addr()
     addr1 = dev[1].p2p_dev_addr()
 
-    if "FAIL" not in dev[0].request("P2P_SERV_DISC_EXTERNAL 2"):
+    if "FAIL" not in dev[0].global_request("P2P_SERV_DISC_EXTERNAL 2"):
         raise Exception("Invalid P2P_SERV_DISC_EXTERNAL accepted")
-    if "OK" not in dev[0].request("P2P_SERV_DISC_EXTERNAL 1"):
+    if "OK" not in dev[0].global_request("P2P_SERV_DISC_EXTERNAL 1"):
         raise Exception("P2P_SERV_DISC_EXTERNAL failed")
     dev[0].p2p_listen()
-    dev[1].request("P2P_FLUSH")
-    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    dev[1].global_request("P2P_FLUSH")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
     if not dev[1].discover_peer(addr0, social=True, force_find=True):
         raise Exception("Peer " + addr0 + " not found")
 
@@ -348,10 +349,10 @@
         raise Exception("Unexpected response data SD Response: " + ev)
     ver = ev.split(' ')[3]
 
-    dev[0].request("P2P_SERVICE_UPDATE")
+    dev[0].global_request("P2P_SERVICE_UPDATE")
 
-    dev[1].request("P2P_FLUSH")
-    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    dev[1].global_request("P2P_FLUSH")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
     if not dev[1].discover_peer(addr0, social=True, force_find=True):
         raise Exception("Peer " + addr0 + " not found")
 
@@ -391,7 +392,7 @@
     try:
         _test_p2p_service_discovery_external(dev)
     finally:
-        dev[0].request("P2P_SERV_DISC_EXTERNAL 0")
+        dev[0].global_request("P2P_SERV_DISC_EXTERNAL 0")
 
 def test_p2p_service_discovery_invalid_commands(dev):
     """P2P service discovery invalid commands"""
@@ -404,7 +405,7 @@
                  "upnp 10",
                  "upnp qq uuid:",
                  "foo bar" ]:
-        if "FAIL" not in dev[0].request("P2P_SERVICE_ADD " + cmd):
+        if "FAIL" not in dev[0].global_request("P2P_SERVICE_ADD " + cmd):
             raise Exception("Invalid P2P_SERVICE_ADD accepted: " + cmd)
 
     for cmd in [ "bonjour",
@@ -414,5 +415,98 @@
                  "upnp  ",
                  "upnp qq uuid:",
                  "foo bar" ]:
-        if "FAIL" not in dev[0].request("P2P_SERVICE_DEL " + cmd):
+        if "FAIL" not in dev[0].global_request("P2P_SERVICE_DEL " + cmd):
             raise Exception("Invalid P2P_SERVICE_DEL accepted: " + cmd)
+
+def test_p2p_service_discovery_cancel_during_query(dev):
+    """P2P service discovery and cancel during query"""
+    for i in range(2):
+        add_bonjour_services(dev[i])
+        add_upnp_services(dev[i])
+        add_extra_services(dev[i])
+        dev[i].p2p_listen()
+
+    dev[2].request("P2P_FLUSH")
+    id1 = dev[2].request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000201")
+    id2 = dev[2].request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000101")
+    dev[2].p2p_find(social=True)
+    ev = dev[2].wait_global_event(["P2P-DEVICE-FOUND"], timeout=15)
+    if ev is None:
+        raise Exception("Could not discover peer")
+    if "OK" not in dev[2].request("P2P_SERV_DISC_CANCEL_REQ " + id1):
+        raise Exception("Failed to cancel req1")
+    if "OK" not in dev[2].request("P2P_SERV_DISC_CANCEL_REQ " + id2):
+        raise Exception("Failed to cancel req2")
+    ev = dev[2].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=3)
+    # we may or may not get a response depending on timing, so ignore the result
+    dev[2].p2p_stop_find()
+    dev[1].p2p_stop_find()
+    dev[0].p2p_stop_find()
+
+def get_p2p_state(dev):
+    res = dev.global_request("STATUS")
+    p2p_state = None
+    for line in res.splitlines():
+        if line.startswith("p2p_state="):
+            p2p_state = line.split('=')[1]
+            break
+    if p2p_state is None:
+        raise Exception("Could not get p2p_state")
+    return p2p_state
+
+def test_p2p_service_discovery_peer_not_listening(dev):
+    """P2P service discovery and peer not listening"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    add_bonjour_services(dev[0])
+    add_upnp_services(dev[0])
+    dev[0].p2p_listen()
+    dev[1].global_request("P2P_FIND 1 type=social")
+    ev = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=4)
+    if ev is None:
+        raise Exception("Peer not found")
+    dev[0].p2p_stop_find()
+    ev = dev[1].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=1)
+    ev = dev[1].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=1)
+    time.sleep(0.03)
+    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    ev = dev[0].wait_global_event(["P2P-SERV-DISC-REQ"], timeout=1)
+    if ev is not None:
+        raise Exception("Service discovery request unexpectedly received")
+    ev = dev[1].wait_global_event(["P2P-FIND-STOPPED", "P2P-SERV-DISC-RESP"],
+                                  timeout=10)
+    if ev is None:
+        raise Exception("P2P-FIND-STOPPED event timed out")
+    if "P2P-SERV-DISC-RESP" in ev:
+        raise Exception("Unexpected SD response")
+    p2p_state = get_p2p_state(dev[1])
+    if p2p_state != "IDLE":
+        raise Exception("Unexpected p2p_state after P2P_FIND timeout: " + p2p_state)
+
+def test_p2p_service_discovery_peer_not_listening2(dev):
+    """P2P service discovery and peer not listening"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    add_bonjour_services(dev[0])
+    add_upnp_services(dev[0])
+    dev[0].p2p_listen()
+    dev[1].global_request("P2P_FIND type=social")
+    ev = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("Peer not found")
+    dev[0].p2p_stop_find()
+    time.sleep(0.53)
+    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
+    ev = dev[0].wait_global_event(["P2P-SERV-DISC-REQ"], timeout=0.5)
+    if ev is not None:
+        raise Exception("Service discovery request unexpectedly received")
+    dev[1].p2p_stop_find()
+    ev = dev[1].wait_global_event(["P2P-FIND-STOPPED", "P2P-SERV-DISC-RESP"],
+                                  timeout=10)
+    if ev is None:
+        raise Exception("P2P-FIND-STOPPED event timed out")
+    if "P2P-SERV-DISC-RESP" in ev:
+        raise Exception("Unexpected SD response")
+    p2p_state = get_p2p_state(dev[1])
+    if p2p_state != "IDLE":
+        raise Exception("Unexpected p2p_state after P2P_FIND timeout: " + p2p_state)
diff --git a/tests/hwsim/test_p2ps.py b/tests/hwsim/test_p2ps.py
new file mode 100644
index 0000000..0f96b3d
--- /dev/null
+++ b/tests/hwsim/test_p2ps.py
@@ -0,0 +1,916 @@
+# P2P services
+# Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger()
+import time
+import random
+
+import hwsim_utils
+from wpasupplicant import WpaSupplicant
+from test_p2p_grpform import check_grpform_results
+from test_p2p_grpform import remove_group
+from test_p2p_persistent import go_neg_pin_authorized_persistent
+
+# Dev[0] -> Advertiser
+# Dev[1] -> Seeker
+# ev0 -> Event generated at advertiser side
+# ev1 -> Event generated at Seeker side
+
+def p2ps_advertise(r_dev, r_role, svc_name, srv_info, rsp_info=None):
+    """P2PS Advertise function"""
+    adv_id = random.randrange(1, 0xFFFFFFFF)
+    advid = hex(adv_id)[2:]
+
+    if rsp_info is not None and srv_info is not None:
+        if "OK" not in r_dev.global_request("P2P_SERVICE_ADD asp " + str(r_role) + " " + str(advid) + " 1 1108 " + svc_name + " svc_info='" + srv_info + "'" + " rsp_info=" + rsp_info + "'"):
+            raise Exception("P2P_SERVICE_ADD with response info and service info failed")
+
+    if rsp_info is None and srv_info is not None:
+        if "OK" not in r_dev.global_request("P2P_SERVICE_ADD asp " + str(r_role) + " " + str(advid) + " 1 1108 " + svc_name + " svc_info='" + srv_info + "'"):
+            raise Exception("P2P_SERVICE_ADD with service info failed")
+
+    if rsp_info is None and srv_info is None:
+        if "OK" not in r_dev.global_request("P2P_SERVICE_ADD asp " + str(r_role) + " " + str(advid) + " 1 1108 " + svc_name + " "):
+            raise Exception("P2P_SERVICE_ADD without service info and without response info failed")
+
+    if rsp_info is not None and srv_info is None:
+        if "OK" not in r_dev.global_request("P2P_SERVICE_ADD asp " + str(r_role) + " " + str(adv_id) + " 1 1108 " + svc_name + " svc_info='" + " rsp_info=" + rsp_info + "'"):
+            raise Exception("P2P_SERVICE_ADD with response info failed")
+
+    r_dev.p2p_listen()
+    return advid
+
+def p2ps_exact_seek(i_dev, r_dev, svc_name, srv_info=None):
+    """P2PS exact service seek request"""
+    if srv_info is not None:
+        ev1 = i_dev.global_request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 asp 1 " + svc_name + " '" + srv_info + "'")
+        if ev1 is None:
+            raise Exception("Failed to add Service Discovery request for exact seek request")
+
+    if "OK" not in i_dev.global_request("P2P_FIND 10 type=social seek=" + svc_name):
+        raise Exception("Failed to initiate seek operation")
+
+    ev1 = i_dev.wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2P-DEVICE-FOUND timeout on seeker side")
+    if r_dev.p2p_dev_addr() not in ev1:
+        raise Exception("Unexpected peer")
+
+    if srv_info is None:
+        adv_id = ev1.split("adv_id=")[1].split(" ")[0]
+        rcvd_svc_name = ev1.split("asp_svc=")[1].split(" ")[0]
+        if rcvd_svc_name != svc_name:
+            raise Exception("service name not matching")
+    else:
+        ev1 = i_dev.wait_global_event(["P2P-SERV-ASP-RESP"], timeout=10)
+        if ev1 is None:
+            raise Exception("Failed to receive Service Discovery Response")
+        if r_dev.p2p_dev_addr() not in ev1:
+            raise Exception("Service Discovery response from Unknown Peer")
+        if srv_info is not None and srv_info not in ev1:
+            raise Exception("service info not available in Service Discovery response")
+        adv_id = ev1.split(" ")[3]
+        rcvd_svc_name = ev1.split(" ")[6]
+        if rcvd_svc_name != svc_name:
+            raise Exception("service name not matching")
+
+    return [adv_id, rcvd_svc_name]
+
+def p2ps_nonexact_seek(i_dev, r_dev, svc_name, srv_info=None, adv_num=None):
+    """P2PS nonexact service seek request"""
+    if adv_num is None:
+       adv_num = 1
+    if srv_info is not None:
+        ev1 = i_dev.global_request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 asp 1 " + svc_name + " '" + srv_info + "'")
+    else:
+        ev1 = i_dev.global_request("P2P_SERV_DISC_REQ 00:00:00:00:00:00 asp 1 " + svc_name + " '")
+    if ev1 is None:
+        raise Exception("Failed to add Service Discovery request for nonexact seek request")
+    if "OK" not in i_dev.global_request("P2P_FIND 10 type=social seek="):
+        raise Exception("Failed to initiate seek")
+    ev1 = i_dev.wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2P-DEVICE-FOUND timeout on seeker side")
+    if r_dev.p2p_dev_addr() not in ev1:
+        raise Exception("Unexpected peer")
+    ev_list = []
+    for i in range (0, adv_num):
+        ev1 = i_dev.wait_global_event(["P2P-SERV-ASP-RESP"], timeout=10)
+        if ev1 is None:
+            raise Exception("Failed to receive Service Discovery Response")
+        if r_dev.p2p_dev_addr() not in ev1:
+            raise Exception("Service Discovery response from Unknown Peer")
+        if srv_info is not None and srv_info not in ev1:
+            raise Exception("service info not available in Service Discovery response")
+        adv_id = ev1.split(" ")[3]
+        rcvd_svc_name = ev1.split(" ")[6]
+        ev_list.append(''.join([adv_id, ' ', rcvd_svc_name]))
+    return ev_list
+
+def p2p_connect_p2ps_method(i_dev, r_dev, autoaccept):
+    """P2PS connect function with p2ps method"""
+    if autoaccept == False:
+        if "OK" not in i_dev.global_request("P2P_CONNECT " + r_dev.p2p_dev_addr() + " 12345670 p2ps persistent auth"):
+            raise Exception("P2P_CONNECT fails on seeker side")
+        ev0 = r_dev.wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+        if ev0 is None:
+            raise Exception("P2PS-PROV-DONE timeout on Advertiser side")
+
+        if "OK" not in r_dev.global_request("P2P_CONNECT " + i_dev.p2p_dev_addr() + " 12345670 p2ps persistent"):
+            raise Exception("P2P_CONNECT fails on Advertiser side")
+
+    else:
+        if "OK" not in r_dev.global_request("P2P_CONNECT " + i_dev.p2p_dev_addr() + " 12345670 p2ps persistent auth"):
+            raise Exception("P2P_CONNECT fails on Advertiser side")
+        ev1 = i_dev.wait_global_event(["P2PS-PROV-DONE"], timeout=5)
+        if ev1 is None:
+            raise Exception("Failed to receive deferred acceptance at seeker")
+
+        if "OK" not in i_dev.global_request("P2P_CONNECT " + r_dev.p2p_dev_addr() + " 12345670 p2ps persistent"):
+            raise Exception("P2P_CONNECT fails on seeker side")
+    ev0 = r_dev.wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=10)
+    if ev0 is None:
+        raise Exception("GO Neg did not succeed")
+    ev0 = r_dev.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+    ev1 = i_dev.wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+def p2ps_provision_keypad_method(i_dev, r_dev, autoaccept,
+                                 initiator_or_responder):
+    """P2PS keypad method provisioning function"""
+    if autoaccept == False and initiator_or_responder == 'initiator':
+        ev = i_dev.wait_global_event(["P2P-PROV-DISC-FAILURE"], timeout=10)
+        if ev is None:
+            raise Exception("Provisioning deferred on seeker side")
+        ev1 = i_dev.wait_global_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=10)
+        if ev1 is None:
+            raise Exception("P2P-PROV-DISC-ENTER-PIN timeout on seeker side")
+        if r_dev.p2p_dev_addr() not in ev1:
+            raise Exception("Unknown peer ")
+        ev = r_dev.wait_global_event(["P2PS-PROV-START"], timeout=10)
+        if ev is None:
+            raise Exception("P2PS-PROV-START timeout on Advertiser side")
+
+    if autoaccept == False and initiator_or_responder == 'responder':
+        ev0 = r_dev.wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+        if ev0 is None:
+            raise Exception("P2PS-PROV-DONE timeout on seeker side")
+        ev0 = r_dev.wait_global_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=5)
+        if ev0 is None:
+            raise Exception("P2P-PROV-DISC-ENTER-PIN timeout on advertiser side")
+
+    if autoaccept == True and initiator_or_responder == 'initiator':
+        ev1 = i_dev.wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+        if ev1 is None:
+            raise Exception("P2PS-PROV-DONE timeout on seeker side")
+        ev1 = i_dev.wait_global_event(["P2P-PROV-DISC-ENTER-PIN"], timeout=10)
+        if ev1 is None:
+            raise Exception("P2P-PROV-DISC-ENTER-PIN failed on seeker side")
+        if r_dev.p2p_dev_addr() not in ev1:
+            raise Exception("Unknown peer ")
+        return ev1
+
+def p2ps_provision_display_method(i_dev, r_dev, autoaccept,
+                                  initiator_or_responder):
+    """P2PS display method provisioning function"""
+    if initiator_or_responder == 'initiator':
+        ev0 = r_dev.wait_global_event(["P2PS-PROV-START"], timeout=10)
+        if ev0 is None:
+            raise Exception("P2PS-PROV-START timeout on Advertiser side")
+        if autoaccept == False:
+            ev = i_dev.wait_global_event(["P2P-PROV-DISC-FAILURE"], timeout=10)
+            if ev is None:
+                raise Exception("Provisioning deferred on seeker side")
+        ev1 = i_dev.wait_global_event(["P2P-PROV-DISC-SHOW-PIN"], timeout=10)
+        if ev1 is None:
+            raise Exception("P2P-PROV-DISC-SHOW-PIN timeout on Seeker side")
+        if r_dev.p2p_dev_addr() not in ev1:
+            raise Exception("Unknown peer ")
+        pin = ev1.split(" ")[2]
+    else:
+        ev0 = r_dev.wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+        if ev0 is None:
+            raise Exception("P2PS-PROV-DONE timeout on advertiser")
+        ev0 = r_dev.wait_global_event(["P2P-PROV-DISC-SHOW-PIN"], timeout=5)
+        if ev0 is None:
+            raise Exception("PIN Display on advertiser side")
+        pin = ev0.split(" ")[2]
+    return pin
+
+def p2ps_connect_pin(pin, i_dev, r_dev, initiator_method):
+    """P2PS function to perform connection using PIN method"""
+    if initiator_method=="display":
+        if "OK" not in i_dev.global_request("P2P_CONNECT " + r_dev.p2p_dev_addr() + " " + pin + " display persistent "):
+            raise Exception("P2P_CONNECT fails on seeker side")
+        ev0 = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
+        if ev0 is None:
+            raise Exception("Failed to receive P2P_GO-NEG-REQUEST on responder side")
+        if "OK" not in r_dev.global_request("P2P_CONNECT " + i_dev.p2p_dev_addr() + " " + pin + " keypad persistent "):
+            raise Exception("P2P_CONNECT fails on Advertiser side")
+    else:
+        if "OK" not in i_dev.global_request("P2P_CONNECT " + r_dev.p2p_dev_addr() + " " + pin + " keypad persistent "):
+            raise Exception("P2P_CONNECT fails on seeker side")
+        ev0 = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
+        if ev0 is None:
+            raise Exception("Failed to receive P2P_GO-NEG-REQUEST on responder side")
+        if "OK" not in r_dev.global_request("P2P_CONNECT " + i_dev.p2p_dev_addr() + " " + pin + " display persistent "):
+            raise Exception("P2P_CONNECT fails on Advertiser side")
+
+    ev0 = r_dev.wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=10)
+    if ev0 is None:
+        raise Exception("GO Neg did not succeed on advertiser side")
+    peer_mac = ev0.split("peer_dev=")[1].split(" ")[0]
+
+    ev1 = i_dev.wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+    ev_grpfrm = r_dev.wait_global_event(["P2P-GROUP-FORMATION-SUCCESS"],
+                                        timeout=10)
+    if ev_grpfrm is None:
+        raise Exception("Group Formation failed on advertiser side")
+
+    ev = r_dev.wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+    Role = ev.split(" ")[2]
+    if Role == "GO":
+        ev_grpfrm = r_dev.wait_global_event(["AP-STA-CONNECTED"], timeout=10)
+        if ev_grpfrm is None:
+            raise Exception("AP-STA-CONNECTED timeout on advertiser side")
+        if i_dev.p2p_dev_addr() not in ev_grpfrm:
+            raise Exception("Group formed with unknown Peer")
+    else:
+        ev1 = i_dev.wait_global_event(["AP-STA-CONNECTED"], timeout=5)
+        if ev1 is None:
+            raise Exception("AP-STA-CONNECTED timeout on Seeker side")
+    if r_dev.p2p_dev_addr() not in ev1:
+        raise Exception("Group formed with unknown Peer")
+
+def test_p2ps_exact_search(dev):
+    """P2PS exact service request"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx')
+
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+
+def test_p2ps_exact_search_srvinfo(dev):
+    """P2PS exact service request with service info"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+
+def test_p2ps_nonexact_search(dev):
+    """P2PS nonexact seek request"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.play.rx',
+                   srv_info='I support Miracast Mode ')
+    ev_list = p2ps_nonexact_seek(i_dev=dev[1], r_dev=dev[0],
+                                 svc_name='org.wi-fi.wfds.play*')
+    adv_id = ev_list[0].split(" ")[0]
+
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+
+def test_p2ps_nonexact_search_srvinfo(dev):
+    """P2PS nonexact seek request with service info"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    ev_list = p2ps_nonexact_seek(i_dev=dev[1], r_dev=dev[0],
+                                 svc_name='org.wi-fi.wfds.send*',
+                                 srv_info='2 GB')
+    adv_id = ev_list[0].split(" ")[0]
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+
+def test_p2ps_connect_p2ps_method_nonautoaccept(dev):
+    """P2PS connect for non-auto-accept and P2PS config method"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    ev_list = p2ps_nonexact_seek(i_dev=dev[1], r_dev=dev[0],
+                                 svc_name='org.wi-fi.wfds.send*',
+                                 srv_info='2 GB')
+    adv_id = ev_list[0].split(" ")[0]
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=1000"):
+        raise Exception("Failed to request provisioning on seeker")
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-START"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2PS-PROV-START timeout on advertiser side")
+    ev1 = dev[1].wait_global_event(["P2P-PROV-DISC-FAILURE"], timeout=15)
+    if ev1 is None:
+        raise Exception("Provisioning deferred timeout on seeker side")
+    dev[1].p2p_listen()
+    if "OK" not in dev[0].global_request("P2P_ASP_PROVISION_RESP " + addr1 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " status=12"):
+        raise Exception("Failed to send deferred acceptance from advertizer")
+    ev1 = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=15)
+    if ev1 is None:
+        raise Exception("Failed to receive deferred acceptance at seeker")
+
+    p2p_connect_p2ps_method(i_dev=dev[1], r_dev=dev[0], autoaccept=False)
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_p2ps_method_autoaccept(dev):
+    """P2PS connection with P2PS default config method and auto-accept"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=1000"):
+        raise Exception("P2P_ASP_PROVISION failed on seeker side")
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2PS-PROV-DONE timeout on advertiser side")
+
+    p2p_connect_p2ps_method(i_dev=dev[1], r_dev=dev[0], autoaccept=True)
+
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_keypad_method_nonautoaccept(dev):
+    """P2PS Connection with non-auto-accept and seeker having keypad method"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    ev_list = p2ps_nonexact_seek(i_dev=dev[1], r_dev=dev[0],
+                                 svc_name='org.wi-fi.wfds.send*',
+                                 srv_info='2 GB')
+    adv_id = ev_list[0].split(" ")[0]
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=8"):     # keypad method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+    p2ps_provision_keypad_method(i_dev=dev[1], r_dev=dev[0], autoaccept=False,
+                                 initiator_or_responder='initiator')
+    dev[1].p2p_listen()
+
+    if "OK" not in dev[0].global_request("P2P_ASP_PROVISION_RESP " + addr1 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " status=12"):
+        raise Exception("Failed to send deferred acceptance from advertizer")
+
+    pin = p2ps_provision_display_method(i_dev=dev[1], r_dev=dev[0],
+                                        autoaccept=False,
+                                        initiator_or_responder='responder')
+    p2ps_connect_pin(pin, i_dev=dev[0], r_dev=dev[1],
+                     initiator_method="display")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_display_method_nonautoaccept(dev):
+    """P2PS connection with non-auto-accept and seeker having display method"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    ev_list = p2ps_nonexact_seek(i_dev=dev[1], r_dev=dev[0],
+                                 svc_name='org.wi-fi.wfds*', srv_info='2 GB')
+    adv_id = ev_list[0].split(" ")[0]
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=100"):     # keypad method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+    pin = p2ps_provision_display_method(i_dev=dev[1], r_dev=dev[0],
+                                        autoaccept=False,
+                                        initiator_or_responder='initiator')
+    dev[1].p2p_listen()
+
+    if "OK" not in dev[0].global_request("P2P_ASP_PROVISION_RESP " + addr1 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " status=12"):
+        raise Exception("Failed to send deferred acceptance from advertiser")
+    p2ps_provision_keypad_method(i_dev=dev[1], r_dev=dev[0], autoaccept=False,
+                                 initiator_or_responder='responder')
+    p2ps_connect_pin(pin, i_dev=dev[0], r_dev=dev[1], initiator_method="keypad")
+
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_keypad_method_autoaccept(dev):
+    """P2PS connection with auto-accept and keypad method on seeker side"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=8"):     # keypad method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+
+    p2ps_provision_keypad_method(i_dev=dev[1], r_dev=dev[0], autoaccept=True,
+                                 initiator_or_responder='initiator')
+    pin = p2ps_provision_display_method(i_dev=dev[1], r_dev=dev[0],
+                                        autoaccept=True,
+                                        initiator_or_responder='responder')
+    p2ps_connect_pin(pin, i_dev=dev[1], r_dev=dev[0], initiator_method="Keypad")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_display_method_autoaccept(dev):
+    """P2PS connection with auto-accept and display method on seeker side"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=100"):     # display method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+
+    pin = p2ps_provision_display_method(i_dev=dev[1], r_dev=dev[0],
+                                        autoaccept=True,
+                                        initiator_or_responder='initiator')
+    dev[1].p2p_listen()
+
+    p2ps_connect_pin(pin, i_dev=dev[1], r_dev=dev[0], initiator_method="display")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_adv_go_p2ps_method(dev):
+    """P2PS auto-accept connection with advertisement as GO and P2PS method"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='4', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=1000"):
+        raise Exception("Failed to request provisioning on seeker")
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("Timed out while waiting for prov done on advertizer")
+    if "go=" not in ev0:
+        raise Exception("Advertiser failed to become GO")
+
+    adv_conncap = ev0.split("conncap=")[1].split(" ")[0]
+    if adv_conncap == "4":
+        logger.info("Advertiser is GO")
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+
+    ev1 = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2PS-PROV-DONE timeout on seeker side")
+
+    seeker_conncap = ev1.split("conncap=")[1].split(" ")[0]
+
+    if "join=" in ev1:
+        if "OK" not in dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 p2ps persistent join"):
+            raise Exception("P2P_CONNECT failed on seeker side")
+        ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+        if ev1 is None:
+            raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+    ev0 = dev[0].wait_global_event(["AP-STA-CONNECTED"], timeout=5)
+    if ev0 is None:
+        raise Exception("AP-STA-CONNECTED timeout on advertiser side")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_adv_client_p2ps_method(dev):
+    """P2PS auto-accept connection with advertisement as Client and P2PS method"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='2', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=1000"):
+        raise Exception("Failed to request provisioning on seeker")
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2PS-PROV-DONE timeout on advertiser side")
+    if "join=" not in ev0:
+        raise Exception("Advertiser failed to become Client")
+
+    adv_conncap = ev0.split("conncap=")[1].split(" ")[0]
+    if adv_conncap == "2":
+        logger.info("Advertiser is Client")
+
+    ev1 = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=5)
+    if ev1 is None:
+        raise Exception("Provisioning failed on seeker side")
+
+    seeker_conncap = ev1.split("conncap=")[1].split(" ")[0]
+    ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+    if "join=" in ev0:
+        if "OK" not in dev[0].global_request("P2P_CONNECT " + addr1 + " 12345670 p2ps persistent join"):
+            raise Exception("P2P_CONNECT failed on seeker side")
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-FORMATION-SUCCESS"], timeout=15)
+    if ev0 is None:
+        raise Exception("P2P Group Formation failed on advertiser side")
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+
+    ev1 = dev[1].wait_global_event(["AP-STA-CONNECTED"], timeout=5)
+    if ev1 is None:
+        raise Exception("Group formation failed")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_adv_go_pin_method(dev):
+    """P2PS advertiser as GO with keypad config method on seeker side and auto-accept"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    p2ps_advertise(r_dev=dev[0], r_role='4', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=8"):     # keypad method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+
+    seek_prov_ev = p2ps_provision_keypad_method(i_dev=dev[1], r_dev=dev[0],
+                                                autoaccept=True,
+                                                initiator_or_responder='initiator')
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2PS-PROV-DONE timeout on advertier side")
+    adv_conncap = ev0.split("conncap=")[1].split(" ")[0]
+    if adv_conncap == "4":
+        logger.info("Advertiser is GO")
+    ev0 = dev[0].wait_global_event(["P2P-PROV-DISC-SHOW-PIN"], timeout=5)
+    if ev0 is None:
+        raise Exception("PIN Display on advertiser side")
+    pin = ev0.split(" ")[2]
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+    ev0 = dev[0].group_request("WPS_PIN any " + pin)
+    if ev0 is None:
+        raise Exception("Failed to initiate Pin authorization on registrar side")
+    if "join=" in seek_prov_ev:
+        if "OK" not in dev[1].global_request("P2P_CONNECT " + addr0 + " " + pin + " keypad persistent join"):
+            raise Exception("P2P_CONNECT failed on seeker side")
+        ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev1 is None:
+            raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+        ev0 = dev[0].wait_global_event(["AP-STA-CONNECTED"], timeout=10)
+        if ev0 is None:
+            raise Exception("AP-STA-CONNECTED timeout on advertiser side")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_connect_adv_client_pin_method(dev):
+    """P2PS advertiser as client with keypad config method on seeker side and auto-accept"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    dev[0].flush_scan_cache()
+    p2ps_advertise(r_dev=dev[0], r_role='2', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=8"):     # keypad method on seeker side
+        raise Exception("Failed to request provisioning on seeker")
+
+    seek_prov_ev = p2ps_provision_keypad_method(i_dev=dev[1], r_dev=dev[0],
+                                                autoaccept=True,
+                                                initiator_or_responder='initiator')
+
+    adv_prov = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if adv_prov is None:
+        raise Exception("Prov failed on advertiser")
+    adv_conncap = adv_prov.split("conncap=")[1].split(" ")[0]
+    if adv_conncap == "2":
+        logger.info("Advertiser is Client")
+    adv_pin_show_event = dev[0].wait_global_event(["P2P-PROV-DISC-SHOW-PIN"],
+                                                  timeout=5)
+    if adv_pin_show_event is None:
+        raise Exception("PIN Display on advertiser side")
+    pin = adv_pin_show_event.split(" ")[2]
+
+    ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+    ev1 = dev[1].group_request("WPS_PIN any " + pin)
+    if ev1 is None:
+        raise Exception("Failed to initiate Pin authorization on registrar side")
+
+    if "join=" in adv_prov:
+        if "OK" not in dev[0].global_request("P2P_CONNECT " + addr1 + " " + pin + " display persistent join"):
+            raise Exception("P2P_CONNECT failed on advertiser side")
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev0 is None:
+        raise Exception("Group formation failed to start on seeker side")
+
+    ev1 = dev[1].wait_global_event(["AP-STA-CONNECTED"], timeout=10)
+    if ev1 is None:
+        raise Exception("AP-STA-CONNECTED timeout on advertiser side")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
+
+def test_p2ps_service_discovery_multiple_queries(dev):
+    """P2P service discovery with multiple queries"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    adv_id1 = p2ps_advertise(r_dev=dev[0], r_role='0',
+                             svc_name='org.wi-fi.wfds.send.tx',
+                             srv_info='I can transfer files upto size of 2 GB')
+    adv_id2 = p2ps_advertise(r_dev=dev[0], r_role='0',
+                             svc_name='org.wi-fi.wfds.send.rx',
+                             srv_info='I can receive files upto size of 2 GB')
+    adv_id3 = p2ps_advertise(r_dev=dev[0], r_role='1',
+                             svc_name='org.wi-fi.wfds.display.tx',
+                             srv_info='Miracast Mode')
+    adv_id4 = p2ps_advertise(r_dev=dev[0], r_role='1',
+                             svc_name='org.wi-fi.wfds.display.rx',
+                             srv_info='Miracast Mode')
+
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " asp 1 org.wi-fi.wfds.display.tx 'Miracast Mode'")
+    dev[1].global_request("P2P_FIND 10 type=social seek=org.wi-fi.wfds.display.tx")
+    dev[1].global_request("P2P_SERV_DISC_REQ " + addr0 + " asp 2 org.wi-fi.wfds.send* 'size of 2 GB'")
+    dev[1].p2p_stop_find()
+    dev[1].global_request("P2P_FIND 10 type=social seek=")
+    ev = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("P2P Device Found timed out")
+    if addr0 not in ev:
+        raise Exception("Unexpected service discovery request source")
+    ev_list = []
+    for i in range(0, 3):
+        ev = dev[1].wait_global_event(["P2P-SERV-ASP-RESP"], timeout=10)
+        if ev is None:
+            raise Exception("P2P Service discovery timed out")
+        if addr0 in ev:
+            ev_list.append(ev)
+            if len(ev_list) == 3:
+                break
+    dev[1].p2p_stop_find()
+
+    for test in [ ("seek=org.wi-fi.wfds.display.TX",
+                   "asp_svc=org.wi-fi.wfds.display.tx"),
+                  ("seek=foo seek=org.wi-fi.wfds.display.tx seek=bar",
+                   "asp_svc=org.wi-fi.wfds.display.tx"),
+                  ("seek=1 seek=2 seek=3 seek=org.wi-fi.wfds.display.tx seek=4 seek=5 seek=6",
+                   "asp_svc=org.wi-fi.wfds.display.tx"),
+                  ("seek=not-found", None),
+                  ("seek=org.wi-fi.wfds", "asp_svc=org.wi-fi.wfds")]:
+        dev[2].global_request("P2P_FIND 10 type=social " + test[0])
+        if test[1] is None:
+            ev = dev[2].wait_global_event(["P2P-DEVICE-FOUND"], timeout=1)
+            if ev is not None:
+                raise Exception("Unexpected device found: " + ev)
+            continue
+        ev = dev[2].wait_global_event(["P2P-DEVICE-FOUND"], timeout=10)
+        if ev is None:
+            raise Exception("P2P device discovery timed out (dev2)")
+            if test[1] not in ev:
+                raise Exception("Expected asp_svc not reported: " + ev)
+        dev[2].p2p_stop_find()
+        dev[2].request("P2P_FLUSH")
+
+    dev[0].p2p_stop_find()
+
+    ev1 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id1))
+    if ev1 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    ev2 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id2))
+    if ev2 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    ev3 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id3))
+    if ev3 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    ev4 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id4))
+    if ev4 is None:
+        raise Exception("Unable to remove the advertisement instance")
+
+    if "OK" not in dev[0].global_request("P2P_SERVICE_ADD asp 1 12345678 1 1108 org.wi-fi.wfds.foobar svc_info='Test'"):
+        raise Exception("P2P_SERVICE_ADD failed")
+    if "OK" not in dev[0].global_request("P2P_SERVICE_DEL asp all"):
+        raise Exception("P2P_SERVICE_DEL asp all failed")
+    if "OK" not in dev[0].global_request("P2P_SERVICE_ADD asp 1 12345678 1 1108 org.wi-fi.wfds.foobar svc_info='Test'"):
+        raise Exception("P2P_SERVICE_ADD failed")
+    if "OK" not in dev[0].global_request("P2P_SERVICE_REP asp 1 12345678 1 1108 org.wi-fi.wfds.foobar svc_info='Test'"):
+        raise Exception("P2P_SERVICE_REP failed")
+    if "FAIL" not in dev[0].global_request("P2P_SERVICE_REP asp 1 12345678 1 1108 org.wi-fi.wfds.Foo svc_info='Test'"):
+        raise Exception("Invalid P2P_SERVICE_REP accepted")
+    if "OK" not in dev[0].global_request("P2P_SERVICE_ADD asp 1 a2345678 1 1108 org.wi-fi.wfds.something svc_info='Test'"):
+        raise Exception("P2P_SERVICE_ADD failed")
+    if "OK" not in dev[0].global_request("P2P_SERVICE_ADD asp 1 a2345679 1 1108 org.wi-fi.wfds.Foo svc_info='Test'"):
+        raise Exception("P2P_SERVICE_ADD failed")
+
+def get_ifnames():
+    with open('/proc/net/dev', 'r') as f:
+        data = f.read()
+    ifnames = []
+    for line in data.splitlines():
+        ifname = line.strip().split(' ')[0]
+        if ':' not in ifname:
+            continue
+        ifname = ifname.split(':')[0]
+        ifnames.append(ifname)
+    return ifnames
+
+def p2ps_connect_p2ps_method(dev):
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    dev[0].flush_scan_cache()
+    dev[1].flush_scan_cache()
+    p2ps_advertise(r_dev=dev[0], r_role='2', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='test-session-info-data' method=1000"):
+        raise Exception("Failed to request provisioning on seeker")
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2PS-PROV-DONE timeout on advertiser side")
+    if "join=" not in ev0:
+        raise Exception("join parameter missing from P2PS-PROV-DONE")
+
+    ev1 = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=5)
+    if ev1 is None:
+        raise Exception("Provisioning failed on seeker side")
+
+    ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+    res1 = dev[1].group_form_result(ev1)
+    ifnames1 = get_ifnames()
+
+    if "OK" not in dev[0].global_request("P2P_CONNECT " + addr1 + " 12345670 p2ps persistent join"):
+        raise Exception("P2P_CONNECT failed on seeker side")
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+    res0 = dev[0].group_form_result(ev0)
+
+    ev1 = dev[1].wait_global_event(["AP-STA-CONNECTED"], timeout=5)
+    if ev1 is None:
+        raise Exception("Group formation failed")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    ifnames2 = get_ifnames()
+    remove_group(dev[0], dev[1])
+    ifnames3 = get_ifnames()
+    return (res0, res1, ifnames1 + ifnames2 + ifnames3)
+
+def has_string_prefix(vals, prefix):
+    for val in vals:
+        if val.startswith(prefix):
+            return True
+    return False
+
+def test_p2ps_connect_p2ps_method_1(dev):
+    """P2PS connection with P2PS method - no group interface"""
+    (res0, res1, ifnames) = p2ps_connect_p2ps_method(dev)
+    if res0['ifname'] != dev[0].ifname:
+        raise Exception("unexpected dev0 group ifname: " + res0['ifname'])
+    if res1['ifname'] != dev[1].ifname:
+        raise Exception("unexpected dev1 group ifname: " + res1['ifname'])
+    if has_string_prefix(ifnames, 'p2p-' + res0['ifname']):
+        raise Exception("dev0 group interface unexpectedly present")
+    if has_string_prefix(ifnames, 'p2p-' + res1['ifname']):
+        raise Exception("dev1 group interface unexpectedly present")
+
+def test_p2ps_connect_p2ps_method_2(dev):
+    """P2PS connection with P2PS method - group interface on dev0"""
+    dev[0].request("SET p2p_no_group_iface 0")
+    (res0, res1, ifnames) = p2ps_connect_p2ps_method(dev)
+    if not res0['ifname'].startswith('p2p-' + dev[0].ifname + '-'):
+        raise Exception("unexpected dev0 group ifname: " + res0['ifname'])
+    if res1['ifname'] != dev[1].ifname:
+        raise Exception("unexpected dev1 group ifname: " + res1['ifname'])
+    if has_string_prefix(ifnames, 'p2p-' + res0['ifname']):
+        raise Exception("dev0 group interface unexpectedly present")
+
+def test_p2ps_connect_p2ps_method_3(dev):
+    """P2PS connection with P2PS method - group interface on dev1"""
+    dev[1].request("SET p2p_no_group_iface 0")
+    (res0, res1, ifnames) = p2ps_connect_p2ps_method(dev)
+    if res0['ifname'] != dev[0].ifname:
+        raise Exception("unexpected dev0 group ifname: " + res0['ifname'])
+    if not res1['ifname'].startswith('p2p-' + dev[1].ifname + '-'):
+        raise Exception("unexpected dev1 group ifname: " + res1['ifname'])
+    if has_string_prefix(ifnames, 'p2p-' + res0['ifname']):
+        raise Exception("dev0 group interface unexpectedly present")
+
+def test_p2ps_connect_p2ps_method_4(dev):
+    """P2PS connection with P2PS method - group interface on both"""
+    dev[0].request("SET p2p_no_group_iface 0")
+    dev[1].request("SET p2p_no_group_iface 0")
+    (res0, res1, ifnames) = p2ps_connect_p2ps_method(dev)
+    if not res0['ifname'].startswith('p2p-' + dev[0].ifname + '-'):
+        raise Exception("unexpected dev0 group ifname: " + res0['ifname'])
+    if not res1['ifname'].startswith('p2p-' + dev[1].ifname + '-'):
+        raise Exception("unexpected dev1 group ifname: " + res1['ifname'])
+
+def test_p2ps_connect_adv_go_persistent(dev):
+    """P2PS auto-accept connection with advertisement as GO and having persistent group"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+
+    go_neg_pin_authorized_persistent(i_dev=dev[0], i_intent=15,
+                                     r_dev=dev[1], r_intent=0)
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+
+    p2ps_advertise(r_dev=dev[0], r_role='4', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    if "OK" not in dev[1].global_request("P2P_ASP_PROVISION " + addr0 + " adv_id=" + str(adv_id) + " adv_mac=" + addr0 + " session=1 session_mac=" + addr1 + " info='' method=1000"):
+        raise Exception("Failed to request provisioning on seeker")
+
+    ev0 = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev0 is None:
+        raise Exception("Timed out while waiting for prov done on advertizer")
+    if "persist=" not in ev0:
+        raise Exception("Advertiser did not indicate persistent group")
+    id0 = ev0.split("persist=")[1].split(" ")[0]
+    if "OK" not in dev[0].global_request("P2P_GROUP_ADD persistent=" + id0 + " freq=2412"):
+        raise Exception("Could not re-start persistent group")
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev0 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on advertiser side")
+
+    ev1 = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev1 is None:
+        raise Exception("P2PS-PROV-DONE timeout on seeker side")
+
+    if "persist=" not in ev1:
+        raise Exception("Seeker did not indicate persistent group")
+    id1 = ev1.split("persist=")[1].split(" ")[0]
+    if "OK" not in dev[1].global_request("P2P_GROUP_ADD persistent=" + id1 + " freq=2412"):
+        raise Exception("Could not re-start persistent group")
+
+    ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev1 is None:
+        raise Exception("P2P-GROUP-STARTED timeout on seeker side")
+
+    ev0 = dev[0].wait_global_event(["AP-STA-CONNECTED"], timeout=15)
+    if ev0 is None:
+        raise Exception("AP-STA-CONNECTED timeout on advertiser side")
+    ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+    if ev0 is None:
+        raise Exception("Unable to remove the advertisement instance")
+    remove_group(dev[0], dev[1])
diff --git a/tests/hwsim/test_pmksa_cache.py b/tests/hwsim/test_pmksa_cache.py
index e0e23ee..0899c84 100644
--- a/tests/hwsim/test_pmksa_cache.py
+++ b/tests/hwsim/test_pmksa_cache.py
@@ -11,6 +11,7 @@
 
 import hostapd
 from wpasupplicant import WpaSupplicant
+from utils import alloc_fail
 from test_ap_eap import eap_connect
 
 def test_pmksa_cache_on_roam_back(dev, apdev):
@@ -288,7 +289,7 @@
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("cui", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk-cui",
@@ -297,10 +298,14 @@
     pmksa = dev[0].get_pmksa(bssid)
     if pmksa is None:
         raise Exception("No PMKSA cache entry created")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
 
     dev[0].dump_monitor()
     logger.info("Disconnect and reconnect to the same AP")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].request("RECONNECT")
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
                             "CTRL-EVENT-CONNECTED"], timeout=10)
@@ -332,8 +337,8 @@
         params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
         params['bridge'] = 'ap-br0'
         hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['sudo', 'brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
         eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
                     password_hex="0123456789abcdef0123456789abcdef")
 
@@ -378,8 +383,144 @@
             raise Exception("Unexpected PMKID change")
 
     finally:
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['sudo', 'brctl', 'delbr', 'ap-br0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+
+def test_pmksa_cache_preauth_vlan_enabled(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set)"""
+    try:
+        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+        params['bridge'] = 'ap-br0'
+        params['dynamic_vlan'] = '1'
+        hostapd.add_ap(apdev[0]['ifname'], params)
+        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+                    password_hex="0123456789abcdef0123456789abcdef")
+
+        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+        params['bridge'] = 'ap-br0'
+        params['rsn_preauth'] = '1'
+        params['rsn_preauth_interfaces'] = 'ap-br0'
+        params['dynamic_vlan'] = '1'
+        hostapd.add_ap(apdev[1]['ifname'], params)
+        bssid1 = apdev[1]['bssid']
+        dev[0].scan(freq="2412")
+        success = False
+        status_seen = False
+        for i in range(0, 50):
+            if not status_seen:
+                status = dev[0].request("STATUS")
+                if "Pre-authentication EAPOL state machines:" in status:
+                    status_seen = True
+            time.sleep(0.1)
+            pmksa = dev[0].get_pmksa(bssid1)
+            if pmksa:
+                success = True
+                break
+        if not success:
+            raise Exception("No PMKSA cache entry created from pre-authentication")
+        if not status_seen:
+            raise Exception("Pre-authentication EAPOL status was not available")
+
+        dev[0].scan(freq="2412")
+        if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
+            raise Exception("Scan results missing RSN element info")
+        dev[0].request("ROAM " + bssid1)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+                                "CTRL-EVENT-CONNECTED"], timeout=10)
+        if ev is None:
+            raise Exception("Roaming with the AP timed out")
+        if "CTRL-EVENT-EAP-STARTED" in ev:
+            raise Exception("Unexpected EAP exchange")
+        pmksa2 = dev[0].get_pmksa(bssid1)
+        if pmksa2 is None:
+            raise Exception("No PMKSA cache entry")
+        if pmksa['pmkid'] != pmksa2['pmkid']:
+            raise Exception("Unexpected PMKID change")
+
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+
+def test_pmksa_cache_preauth_vlan_used(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry (station with VLAN set)"""
+    try:
+        subprocess.call(['brctl', 'addbr', 'brvlan1'])
+        subprocess.call(['brctl', 'setfd', 'brvlan1', '0'])
+        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+        params['bridge'] = 'ap-br0'
+        params['dynamic_vlan'] = '1'
+        params['vlan_file'] = 'hostapd.wlan3.vlan'
+        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        eap_connect(dev[0], apdev[0], "PAX", "vlan1",
+                    password_hex="0123456789abcdef0123456789abcdef")
+
+        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+        params['bridge'] = 'ap-br0'
+        params['rsn_preauth'] = '1'
+        params['rsn_preauth_interfaces'] = 'brvlan1'
+        params['dynamic_vlan'] = '1'
+        params['vlan_file'] = 'hostapd.wlan4.vlan'
+        hostapd.add_ap(apdev[1]['ifname'], params)
+        bssid1 = apdev[1]['bssid']
+        dev[0].scan(freq="2412")
+        success = False
+        status_seen = False
+        for i in range(0, 50):
+            if not status_seen:
+                status = dev[0].request("STATUS")
+                if "Pre-authentication EAPOL state machines:" in status:
+                    status_seen = True
+            time.sleep(0.1)
+            pmksa = dev[0].get_pmksa(bssid1)
+            if pmksa:
+                success = True
+                break
+        if not success:
+            raise Exception("No PMKSA cache entry created from pre-authentication")
+        if not status_seen:
+            raise Exception("Pre-authentication EAPOL status was not available")
+
+        dev[0].scan(freq="2412")
+        if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
+            raise Exception("Scan results missing RSN element info")
+        dev[0].request("ROAM " + bssid1)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+                                "CTRL-EVENT-CONNECTED"], timeout=10)
+        if ev is None:
+            raise Exception("Roaming with the AP timed out")
+        if "CTRL-EVENT-EAP-STARTED" in ev:
+            raise Exception("Unexpected EAP exchange")
+        pmksa2 = dev[0].get_pmksa(bssid1)
+        if pmksa2 is None:
+            raise Exception("No PMKSA cache entry")
+        if pmksa['pmkid'] != pmksa2['pmkid']:
+            raise Exception("Unexpected PMKID change")
+
+        # Disconnect the STA from both APs to avoid forceful ifdown by the
+        # test script on a VLAN that this has an associated STA. That used to
+        # trigger a mac80211 warning.
+        dev[0].request("DISCONNECT")
+        hapd.request("DISABLE")
+
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['ip', 'link', 'set', 'dev', 'brvlan1', 'down'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'wlan3.1', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['ip', 'link', 'set', 'dev', 'wlan4.1', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan3.1'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan4.1'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'ap-br0'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'brvlan1'])
 
 def test_pmksa_cache_disabled(dev, apdev):
     """PMKSA cache disabling on AP"""
@@ -421,12 +562,15 @@
 def test_pmksa_cache_ap_expiration(dev, apdev):
     """PMKSA cache entry expiring on AP"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk-user-session-timeout",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     dev[0].request("DISCONNECT")
     time.sleep(5)
     dev[0].dump_monitor()
@@ -544,3 +688,141 @@
             raise Exception("Roaming with the AP timed out")
         if "CTRL-EVENT-EAP-STARTED" in ev:
             raise Exception("Unexpected EAP exchange")
+
+def test_pmksa_cache_preauth_oom(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry and OOM"""
+    try:
+        _test_pmksa_cache_preauth_oom(dev, apdev)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
+        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+
+def _test_pmksa_cache_preauth_oom(dev, apdev):
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['bridge'] = 'ap-br0'
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+                password_hex="0123456789abcdef0123456789abcdef",
+                bssid=apdev[0]['bssid'])
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['bridge'] = 'ap-br0'
+    params['rsn_preauth'] = '1'
+    params['rsn_preauth_interfaces'] = 'ap-br0'
+    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+    bssid1 = apdev[1]['bssid']
+
+    tests = [ (1, "rsn_preauth_receive"),
+              (2, "rsn_preauth_receive"),
+              (1, "rsn_preauth_send") ]
+    for test in tests:
+        with alloc_fail(hapd, test[0], test[1]):
+            dev[0].scan_for_bss(bssid1, freq="2412")
+            if "OK" not in dev[0].request("PREAUTH " + bssid1):
+                raise Exception("PREAUTH failed")
+
+            success = False
+            count = 0
+            for i in range(50):
+                time.sleep(0.1)
+                pmksa = dev[0].get_pmksa(bssid1)
+                if pmksa:
+                    success = True
+                    break
+                state = hapd.request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    count += 1
+                    if count > 2:
+                        break
+            logger.info("PMKSA cache success: " + str(success))
+
+            dev[0].request("PMKSA_FLUSH")
+            dev[0].wait_disconnected()
+            dev[0].wait_connected()
+            dev[0].dump_monitor()
+
+def test_pmksa_cache_size_limit(dev, apdev):
+    """PMKSA cache size limit in wpa_supplicant"""
+    try:
+        _test_pmksa_cache_size_limit(dev, apdev)
+    finally:
+        try:
+            hapd = hostapd.HostapdGlobal()
+            hapd.flush()
+            hapd.remove(apdev[0]['ifname'])
+        except:
+            pass
+        params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
+        bssid = apdev[0]['bssid']
+        params['bssid'] = bssid
+        hostapd.add_ap(apdev[0]['ifname'], params)
+
+def _test_pmksa_cache_size_limit(dev, apdev):
+    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
+    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
+                        eap="GPSK", identity="gpsk user",
+                        password="abcdefghijklmnop0123456789abcdef",
+                        scan_freq="2412", only_add_network=True)
+    for i in range(33):
+        bssid = apdev[0]['bssid'][0:15] + "%02x" % i
+        logger.info("Iteration with BSSID " + bssid)
+        params['bssid'] = bssid
+        hostapd.add_ap(apdev[0]['ifname'], params)
+        dev[0].request("BSS_FLUSH 0")
+        dev[0].scan_for_bss(bssid, freq=2412, only_new=True)
+        dev[0].select_network(id)
+        dev[0].wait_connected()
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected()
+        dev[0].dump_monitor()
+        entries = len(dev[0].request("PMKSA").splitlines()) - 1
+        if i == 32:
+            if entries != 32:
+                raise Exception("Unexpected number of PMKSA entries after expected removal of the oldest entry")
+        elif i + 1 != entries:
+            raise Exception("Unexpected number of PMKSA entries")
+
+        hapd = hostapd.HostapdGlobal()
+        hapd.flush()
+        hapd.remove(apdev[0]['ifname'])
+
+def test_pmksa_cache_preauth_timeout(dev, apdev):
+    """RSN pre-authentication timing out"""
+    try:
+        _test_pmksa_cache_preauth_timeout(dev, apdev)
+    finally:
+        dev[0].request("SET dot11RSNAConfigSATimeout 60")
+
+def _test_pmksa_cache_preauth_timeout(dev, apdev):
+    dev[0].request("SET dot11RSNAConfigSATimeout 1")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+                password_hex="0123456789abcdef0123456789abcdef",
+                bssid=apdev[0]['bssid'])
+    if "OK" not in dev[0].request("PREAUTH f2:11:22:33:44:55"):
+        raise Exception("PREAUTH failed")
+    ev = dev[0].wait_event(["RSN: pre-authentication with"], timeout=5)
+    if ev is None:
+        raise Exception("No timeout event seen")
+    if "timed out" not in ev:
+        raise Exception("Unexpected event: " + ev)
+
+def test_pmksa_cache_preauth_wpas_oom(dev, apdev):
+    """RSN pre-authentication OOM in wpa_supplicant"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+                password_hex="0123456789abcdef0123456789abcdef",
+                bssid=apdev[0]['bssid'])
+    for i in range(1, 11):
+        with alloc_fail(dev[0], i, "rsn_preauth_init"):
+            res = dev[0].request("PREAUTH f2:11:22:33:44:55").strip()
+            logger.info("Iteration %d - PREAUTH command results: %s" % (i, res))
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    break
+                time.sleep(0.05)
diff --git a/tests/hwsim/test_radius.py b/tests/hwsim/test_radius.py
index e68747e..891d681 100644
--- a/tests/hwsim/test_radius.py
+++ b/tests/hwsim/test_radius.py
@@ -1,5 +1,5 @@
 # RADIUS tests
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -8,6 +8,7 @@
 import hmac
 import logging
 logger = logging.getLogger()
+import os
 import select
 import struct
 import subprocess
@@ -15,6 +16,7 @@
 import time
 
 import hostapd
+from utils import HwsimSkip, require_under_vm
 
 def connect(dev, ssid, wait_connect=True):
     dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412",
@@ -44,14 +46,13 @@
 
 def test_radius_auth_unreachable2(dev, apdev):
     """RADIUS Authentication server unreachable (2)"""
-    subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
-                     'lo'])
+    subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     params['auth_server_addr'] = "192.168.213.17"
     params['auth_server_port'] = "18139"
     hostapd.add_ap(apdev[0]['ifname'], params)
     hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
+    subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
     connect(dev[0], "radius-auth", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
     if ev is None:
@@ -64,6 +65,25 @@
     if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
         raise Exception("Missing RADIUS Authentication retransmission")
 
+def test_radius_auth_unreachable3(dev, apdev):
+    """RADIUS Authentication server initially unreachable, but then available"""
+    subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
+    params = hostapd.wpa2_eap_params(ssid="radius-auth")
+    params['auth_server_addr'] = "192.168.213.18"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    connect(dev[0], "radius-auth", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
+    time.sleep(0.1)
+    dev[0].request("DISCONNECT")
+    hapd.set('auth_server_addr_replace', '127.0.0.1')
+    dev[0].request("RECONNECT")
+
+    dev[0].wait_connected()
+
 def test_radius_acct_unreachable(dev, apdev):
     """RADIUS Accounting server unreachable"""
     params = hostapd.wpa2_eap_params(ssid="radius-acct")
@@ -85,15 +105,14 @@
 
 def test_radius_acct_unreachable2(dev, apdev):
     """RADIUS Accounting server unreachable(2)"""
-    subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
-                     'lo'])
+    subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
     params = hostapd.wpa2_eap_params(ssid="radius-acct")
     params['acct_server_addr'] = "192.168.213.17"
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
     hostapd.add_ap(apdev[0]['ifname'], params)
     hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
+    subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
     connect(dev[0], "radius-acct")
     logger.info("Checking for RADIUS retries")
     time.sleep(4)
@@ -103,6 +122,45 @@
     if int(mib["radiusAccClientRetransmissions"]) < 1 and int(mib["radiusAccClientPendingRequests"]) < 1:
         raise Exception("Missing pending or retransmitted RADIUS Accounting requests")
 
+def test_radius_acct_unreachable3(dev, apdev):
+    """RADIUS Accounting server initially unreachable, but then available"""
+    require_under_vm()
+    subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
+    as_hapd = hostapd.Hostapd("as")
+    as_mib_start = as_hapd.get_mib(param="radius_server")
+    params = hostapd.wpa2_eap_params(ssid="radius-acct")
+    params['acct_server_addr'] = "192.168.213.18"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    connect(dev[0], "radius-acct")
+    subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
+    time.sleep(0.1)
+    dev[0].request("DISCONNECT")
+    hapd.set('acct_server_addr_replace', '127.0.0.1')
+    dev[0].request("RECONNECT")
+    dev[0].wait_connected()
+    time.sleep(1)
+    as_mib_end = as_hapd.get_mib(param="radius_server")
+    req_s = int(as_mib_start['radiusAccServTotalResponses'])
+    req_e = int(as_mib_end['radiusAccServTotalResponses'])
+    if req_e <= req_s:
+        raise Exception("Unexpected RADIUS server acct MIB value")
+
+def test_radius_acct_unreachable4(dev, apdev):
+    """RADIUS Accounting server unreachable and multiple STAs"""
+    params = hostapd.wpa2_eap_params(ssid="radius-acct")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "18139"
+    params['acct_server_shared_secret'] = "radius"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    for i in range(20):
+        connect(dev[0], "radius-acct")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
 def test_radius_acct(dev, apdev):
     """RADIUS Accounting"""
     as_hapd = hostapd.Hostapd("as")
@@ -229,6 +287,19 @@
     if req_e < req_s + 2:
         raise Exception("Unexpected RADIUS server acct MIB value")
 
+def send_and_check_reply(srv, req, code, error_cause=0):
+    reply = srv.SendPacket(req)
+    logger.debug("RADIUS response from hostapd")
+    for i in reply.keys():
+        logger.debug("%s: %s" % (i, reply[i]))
+    if reply.code != code:
+        raise Exception("Unexpected response code")
+    if error_cause:
+        if 'Error-Cause' not in reply:
+            raise Exception("Missing Error-Cause")
+            if reply['Error-Cause'][0] != error_cause:
+                raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+
 def test_radius_das_disconnect(dev, apdev):
     """RADIUS Dynamic Authorization Extensions - Disconnect"""
     try:
@@ -237,7 +308,7 @@
         import pyrad.dictionary
         import radius_das
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No pyrad modules available")
 
     params = hostapd.wpa2_eap_params(ssid="radius-das")
     params['radius_das_port'] = "3799"
@@ -296,77 +367,55 @@
                                       User_Name="foo",
                                       User_Password="foo",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 401:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 401)
 
     logger.info("Disconnect-Request with invalid Calling-Station-Id")
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       User_Name="foo",
                                       Calling_Station_Id="foo",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 407:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 407)
 
     logger.info("Disconnect-Request with mismatching User-Name")
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       User_Name="foo",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 503:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
 
     logger.info("Disconnect-Request with mismatching Calling-Station-Id")
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       Calling_Station_Id="12:34:56:78:90:aa",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 503:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
 
     logger.info("Disconnect-Request with mismatching Acct-Session-Id")
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       Acct_Session_Id="12345678-87654321",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 503:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
+
+    logger.info("Disconnect-Request with mismatching Acct-Session-Id (len)")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      Acct_Session_Id="12345678",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
+
+    logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      Acct_Multi_Session_Id="12345678+87654321",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
+
+    logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id (len)")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      Acct_Multi_Session_Id="12345678",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
+
+    logger.info("Disconnect-Request with no session identification attributes")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
 
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
@@ -377,32 +426,14 @@
                                       NAS_IP_Address="192.168.3.4",
                                       Acct_Session_Id=id,
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 403:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
 
     logger.info("Disconnect-Request with mismatching NAS-Identifier")
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       NAS_Identifier="unknown.example.com",
                                       Acct_Session_Id=id,
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectNAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 403:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
 
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
@@ -414,12 +445,20 @@
                                       NAS_Identifier="nas.example.com",
                                       Acct_Session_Id=id,
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectACK:
-        raise Exception("Unexpected response code")
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    dev[0].wait_disconnected(timeout=10)
+    dev[0].wait_connected(timeout=10, error="Re-connection timed out")
+
+    logger.info("Disconnect-Request with matching Acct-Multi-Session-Id")
+    sta = hapd.get_sta(addr)
+    multi_sess_id = sta['authMultiSessionId']
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      Acct_Multi_Session_Id=multi_sess_id,
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
 
     dev[0].wait_disconnected(timeout=10)
     dev[0].wait_connected(timeout=10, error="Re-connection timed out")
@@ -429,12 +468,7 @@
                                       NAS_Identifier="nas.example.com",
                                       User_Name="psk.user@example.com",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectACK:
-        raise Exception("Unexpected response code")
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
 
     dev[0].wait_disconnected(timeout=10)
     dev[0].wait_connected(timeout=10, error="Re-connection timed out")
@@ -444,12 +478,7 @@
                                       NAS_IP_Address="127.0.0.1",
                                       Calling_Station_Id=addr,
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectACK:
-        raise Exception("Unexpected response code")
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
 
     dev[0].wait_disconnected(timeout=10)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", "CTRL-EVENT-CONNECTED"])
@@ -464,15 +493,7 @@
                                       Calling_Station_Id=addr,
                                       Chargeable_User_Identity="foo@example.com",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectACK:
-        raise Exception("Unexpected response code")
-
-    dev[0].wait_disconnected(timeout=10)
-    dev[0].wait_connected(timeout=10, error="Re-connection timed out")
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
 
     logger.info("Disconnect-Request with matching CUI")
     dev[1].connect("radius-das", key_mgmt="WPA-EAP",
@@ -482,12 +503,7 @@
     req = radius_das.DisconnectPacket(dict=dict, secret="secret",
                                       Chargeable_User_Identity="gpsk-chargeable-user-identity",
                                       Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.DisconnectACK:
-        raise Exception("Unexpected response code")
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
 
     dev[1].wait_disconnected(timeout=10)
     dev[1].wait_connected(timeout=10, error="Re-connection timed out")
@@ -496,6 +512,93 @@
     if ev is not None:
         raise Exception("Unexpected disconnection")
 
+    connect(dev[2], "radius-das")
+
+    logger.info("Disconnect-Request with matching User-Name - multiple sessions matching")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_Identifier="nas.example.com",
+                                      User_Name="psk.user@example.com",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=508)
+
+    logger.info("Disconnect-Request with User-Name matching multiple sessions, Calling-Station-Id only one")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_Identifier="nas.example.com",
+                                      Calling_Station_Id=addr,
+                                      User_Name="psk.user@example.com",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    dev[0].wait_disconnected(timeout=10)
+    dev[0].wait_connected(timeout=10, error="Re-connection timed out")
+
+    ev = dev[2].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
+    if ev is not None:
+        raise Exception("Unexpected disconnection")
+
+    logger.info("Disconnect-Request with matching Acct-Multi-Session-Id after disassociation")
+    sta = hapd.get_sta(addr)
+    multi_sess_id = sta['authMultiSessionId']
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      Acct_Multi_Session_Id=multi_sess_id,
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    dev[0].request("RECONNECT")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    dev[0].wait_connected(timeout=15)
+
+    logger.info("Disconnect-Request with matching User-Name after disassociation")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    dev[2].request("DISCONNECT")
+    dev[2].wait_disconnected(timeout=10)
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      User_Name="psk.user@example.com",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    logger.info("Disconnect-Request with matching CUI after disassociation")
+    dev[1].request("DISCONNECT")
+    dev[1].wait_disconnected(timeout=10)
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      Chargeable_User_Identity="gpsk-chargeable-user-identity",
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    logger.info("Disconnect-Request with matching Calling-Station-Id after disassociation")
+    dev[0].request("RECONNECT")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    dev[0].wait_connected(timeout=15)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      Calling_Station_Id=addr,
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
+
+    logger.info("Disconnect-Request with mismatching Calling-Station-Id after disassociation")
+    req = radius_das.DisconnectPacket(dict=dict, secret="secret",
+                                      NAS_IP_Address="127.0.0.1",
+                                      NAS_Identifier="nas.example.com",
+                                      Calling_Station_Id=addr,
+                                      Event_Timestamp=int(time.time()))
+    send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
+
 def test_radius_das_coa(dev, apdev):
     """RADIUS Dynamic Authorization Extensions - CoA"""
     try:
@@ -504,7 +607,7 @@
         import pyrad.dictionary
         import radius_das
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No pyrad modules available")
 
     params = hostapd.wpa2_eap_params(ssid="radius-das")
     params['radius_das_port'] = "3799"
@@ -528,16 +631,7 @@
     req = radius_das.CoAPacket(dict=dict, secret="secret",
                                Acct_Session_Id=id,
                                Event_Timestamp=int(time.time()))
-    reply = srv.SendPacket(req)
-    logger.debug("RADIUS response from hostapd")
-    for i in reply.keys():
-        logger.debug("%s: %s" % (i, reply[i]))
-    if reply.code != pyrad.packet.CoANAK:
-        raise Exception("Unexpected response code")
-    if 'Error-Cause' not in reply:
-        raise Exception("Missing Error-Cause")
-    if reply['Error-Cause'][0] != 405:
-        raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
+    send_and_check_reply(srv, req, pyrad.packet.CoANAK, error_cause=405)
 
 def test_radius_ipv6(dev, apdev):
     """RADIUS connection over IPv6"""
@@ -573,10 +667,24 @@
     hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
 
+def test_radius_macacl_acct(dev, apdev):
+    """RADIUS MAC ACL and accounting enabled"""
+    params = hostapd.radius_params()
+    params["ssid"] = "radius"
+    params["macaddr_acl"] = "2"
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
+    dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412")
+    dev[1].request("DISCONNECT")
+    dev[1].wait_disconnected()
+    dev[1].request("RECONNECT")
+
 def test_radius_failover(dev, apdev):
     """RADIUS Authentication and Accounting server failover"""
-    subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
-                     'lo'])
+    subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
     as_hapd = hostapd.Hostapd("as")
     as_mib_start = as_hapd.get_mib(param="radius_server")
     params = hostapd.wpa2_eap_params(ssid="radius-failover")
@@ -586,6 +694,7 @@
     params['acct_server_addr'] = "192.168.213.17"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "testing"
+    params['radius_retry_primary_interval'] = "20"
     hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
     hapd.set("auth_server_addr", "127.0.0.1")
     hapd.set("auth_server_port", "1812")
@@ -599,16 +708,16 @@
         raise Exception("AP startup timed out")
         if "AP-ENABLED" not in ev:
             raise Exception("AP startup failed")
+    start = os.times()[4]
 
     try:
-        subprocess.call(['sudo', 'ip', 'ro', 'replace', 'prohibit',
-                         '192.168.213.17'])
+        subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
         dev[0].request("SET EAPOL::authPeriod 5")
         connect(dev[0], "radius-failover", wait_connect=False)
-        dev[0].wait_connected(timeout=60)
+        dev[0].wait_connected(timeout=20)
     finally:
         dev[0].request("SET EAPOL::authPeriod 30")
-        subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17'])
+        subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
 
     as_mib_end = as_hapd.get_mib(param="radius_server")
     req_s = int(as_mib_start['radiusAccServTotalRequests'])
@@ -616,6 +725,18 @@
     if req_e <= req_s:
         raise Exception("Unexpected RADIUS server acct MIB value")
 
+    end = os.times()[4]
+    try:
+        subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
+        dev[1].request("SET EAPOL::authPeriod 5")
+        if end - start < 21:
+            time.sleep(21 - (end - start))
+        connect(dev[1], "radius-failover", wait_connect=False)
+        dev[1].wait_connected(timeout=20)
+    finally:
+        dev[1].request("SET EAPOL::authPeriod 30")
+        subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
+
 def run_pyrad_server(srv, t_events):
     srv.RunWithStop(t_events)
 
@@ -626,7 +747,7 @@
         import pyrad.packet
         import pyrad.dictionary
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No pyrad modules available")
 
     class TestServer(pyrad.server.Server):
         def _HandleAuthPacket(self, pkt):
@@ -734,7 +855,7 @@
         import pyrad.packet
         import pyrad.dictionary
     except ImportError:
-        return "skip"
+        raise HwsimSkip("No pyrad modules available")
 
     class TestServer(pyrad.server.Server):
         def _HandleAuthPacket(self, pkt):
@@ -815,3 +936,77 @@
     finally:
         t_events['stop'].set()
         t.join()
+
+def test_radius_auth_force_client_addr(dev, apdev):
+    """RADIUS client address specified"""
+    params = hostapd.wpa2_eap_params(ssid="radius-auth")
+    params['radius_client_addr'] = "127.0.0.1"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    connect(dev[0], "radius-auth")
+
+def test_radius_auth_force_invalid_client_addr(dev, apdev):
+    """RADIUS client address specified and invalid address"""
+    params = hostapd.wpa2_eap_params(ssid="radius-auth")
+    #params['radius_client_addr'] = "10.11.12.14"
+    params['radius_client_addr'] = "1::2"
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    connect(dev[0], "radius-auth", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
+    if ev is not None:
+        raise Exception("Unexpected connection")
+
+def add_message_auth(req):
+    req.authenticator = req.CreateAuthenticator()
+    hmac_obj = hmac.new(req.secret)
+    hmac_obj.update(struct.pack("B", req.code))
+    hmac_obj.update(struct.pack("B", req.id))
+
+    # request attributes
+    req.AddAttribute("Message-Authenticator",
+                     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
+    attrs = req._PktEncodeAttributes()
+
+    # Length
+    flen = 4 + 16 + len(attrs)
+    hmac_obj.update(struct.pack(">H", flen))
+    hmac_obj.update(req.authenticator)
+    hmac_obj.update(attrs)
+    del req[80]
+    req.AddAttribute("Message-Authenticator", hmac_obj.digest())
+
+def test_radius_server_failures(dev, apdev):
+    """RADIUS server failure cases"""
+    try:
+        import pyrad.client
+        import pyrad.packet
+        import pyrad.dictionary
+    except ImportError:
+        raise HwsimSkip("No pyrad modules available")
+
+    dict = pyrad.dictionary.Dictionary("dictionary.radius")
+    client = pyrad.client.Client(server="127.0.0.1", authport=1812,
+                                 secret="radius", dict=dict)
+    client.retries = 1
+    client.timeout = 1
+
+    # unexpected State
+    req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
+                                  User_Name="foo")
+    req['State'] = 'foo-state'
+    add_message_auth(req)
+    reply = client.SendPacket(req)
+    if reply.code != pyrad.packet.AccessReject:
+        raise Exception("Unexpected RADIUS response code " + str(reply.code))
+
+    # no EAP-Message
+    req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
+                                  User_Name="foo")
+    add_message_auth(req)
+    try:
+        reply = client.SendPacket(req)
+        raise Exception("Unexpected response")
+    except pyrad.client.Timeout:
+        pass
diff --git a/tests/hwsim/test_rfkill.py b/tests/hwsim/test_rfkill.py
index a0b5b2a..425b40f 100644
--- a/tests/hwsim/test_rfkill.py
+++ b/tests/hwsim/test_rfkill.py
@@ -6,39 +6,34 @@
 
 import logging
 logger = logging.getLogger()
-import subprocess
 import time
 
 import hostapd
 from hostapd import HostapdGlobal
 import hwsim_utils
 from wpasupplicant import WpaSupplicant
+from rfkill import RFKill
+from utils import HwsimSkip
 
-def get_rfkill_id(dev):
-    try:
-        cmd = subprocess.Popen(["rfkill", "list"], stdout=subprocess.PIPE)
-    except Exception, e:
-        logger.info("No rfkill available: " + str(e))
-        return None
-    res = cmd.stdout.read()
-    cmd.stdout.close()
+def get_rfkill(dev):
     phy = dev.get_driver_status_field("phyname")
-    matches = [ line for line in res.splitlines() if phy + ':' in line ]
-    if len(matches) != 1:
-        return None
-    return matches[0].split(':')[0]
+    try:
+        for r, s, h in RFKill.list():
+            if r.name == phy:
+                return r
+    except Exception, e:
+        raise HwsimSkip("No rfkill available: " + str(e))
+    raise HwsimSkip("No rfkill match found for the interface")
 
 def test_rfkill_open(dev, apdev):
     """rfkill block/unblock during open mode connection"""
-    id = get_rfkill_id(dev[0])
-    if id is None:
-        return "skip"
+    rfk = get_rfkill(dev[0])
 
     hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     try:
         logger.info("rfkill block")
-        subprocess.call(['sudo', 'rfkill', 'block', id])
+        rfk.block()
         dev[0].wait_disconnected(timeout=10,
                                  error="Missing disconnection event on rfkill block")
 
@@ -52,18 +47,16 @@
             raise Exception("FETCH_OSU accepted while disabled")
 
         logger.info("rfkill unblock")
-        subprocess.call(['sudo', 'rfkill', 'unblock', id])
+        rfk.unblock()
         dev[0].wait_connected(timeout=10,
                               error="Missing connection event on rfkill unblock")
         hwsim_utils.test_connectivity(dev[0], hapd)
     finally:
-        subprocess.call(['sudo', 'rfkill', 'unblock', id])
+        rfk.unblock()
 
 def test_rfkill_wpa2_psk(dev, apdev):
     """rfkill block/unblock during WPA2-PSK connection"""
-    id = get_rfkill_id(dev[0])
-    if id is None:
-        return "skip"
+    rfk = get_rfkill(dev[0])
 
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
@@ -72,26 +65,22 @@
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     try:
         logger.info("rfkill block")
-        subprocess.call(['sudo', 'rfkill', 'block', id])
+        rfk.block()
         dev[0].wait_disconnected(timeout=10,
                                  error="Missing disconnection event on rfkill block")
 
         logger.info("rfkill unblock")
-        subprocess.call(['sudo', 'rfkill', 'unblock', id])
+        rfk.unblock()
         dev[0].wait_connected(timeout=10,
                               error="Missing connection event on rfkill unblock")
         hwsim_utils.test_connectivity(dev[0], hapd)
     finally:
-        subprocess.call(['sudo', 'rfkill', 'unblock', id])
+        rfk.unblock()
 
 def test_rfkill_autogo(dev, apdev):
     """rfkill block/unblock for autonomous P2P GO"""
-    id0 = get_rfkill_id(dev[0])
-    if id0 is None:
-        return "skip"
-    id1 = get_rfkill_id(dev[1])
-    if id1 is None:
-        return "skip"
+    rfk0 = get_rfkill(dev[0])
+    rfk1 = get_rfkill(dev[1])
 
     dev[0].p2p_start_go()
     dev[1].request("SET p2p_no_group_iface 0")
@@ -99,7 +88,7 @@
 
     try:
         logger.info("rfkill block 0")
-        subprocess.call(['sudo', 'rfkill', 'block', id0])
+        rfk0.block()
         ev = dev[0].wait_global_event(["P2P-GROUP-REMOVED"], timeout=10)
         if ev is None:
             raise Exception("Group removal not reported")
@@ -111,7 +100,7 @@
             raise Exception("P2P_LISTEN accepted unexpectedly")
 
         logger.info("rfkill block 1")
-        subprocess.call(['sudo', 'rfkill', 'block', id1])
+        rfk1.block()
         ev = dev[1].wait_global_event(["P2P-GROUP-REMOVED"], timeout=10)
         if ev is None:
             raise Exception("Group removal not reported")
@@ -119,28 +108,26 @@
             raise Exception("Unexpected group removal reason: " + ev)
 
         logger.info("rfkill unblock 0")
-        subprocess.call(['sudo', 'rfkill', 'unblock', id0])
+        rfk0.unblock()
         logger.info("rfkill unblock 1")
-        subprocess.call(['sudo', 'rfkill', 'unblock', id1])
+        rfk1.unblock()
         time.sleep(1)
     finally:
-        subprocess.call(['sudo', 'rfkill', 'unblock', id0])
-        subprocess.call(['sudo', 'rfkill', 'unblock', id1])
+        rfk0.unblock()
+        rfk1.unblock()
 
 def test_rfkill_hostapd(dev, apdev):
     """rfkill block/unblock during and prior to hostapd operations"""
     hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
 
-    id = get_rfkill_id(hapd)
-    if id is None:
-        return "skip"
+    rfk = get_rfkill(hapd)
 
     try:
-        subprocess.call(['rfkill', 'block', id])
+        rfk.block()
         ev = hapd.wait_event(["INTERFACE-DISABLED"], timeout=5)
         if ev is None:
             raise Exception("INTERFACE-DISABLED event not seen")
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
         ev = hapd.wait_event(["INTERFACE-ENABLED"], timeout=5)
         if ev is None:
             raise Exception("INTERFACE-ENABLED event not seen")
@@ -148,7 +135,7 @@
         hapd.disable()
         hapd.enable()
         dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
-        subprocess.call(['rfkill', 'block', id])
+        rfk.block()
         ev = hapd.wait_event(["INTERFACE-DISABLED"], timeout=5)
         if ev is None:
             raise Exception("INTERFACE-DISABLED event not seen")
@@ -165,27 +152,25 @@
         if "FAIL" not in hapd.request("ENABLE"):
             raise Exception("ENABLE succeeded unexpectedly (rfkill)")
     finally:
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
 
 def test_rfkill_wpas(dev, apdev):
     """rfkill block prior to wpa_supplicant start"""
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
-    id = get_rfkill_id(wpas)
-    if id is None:
-        return "skip"
+    rfk = get_rfkill(wpas)
     wpas.interface_remove("wlan5")
     try:
-        subprocess.call(['rfkill', 'block', id])
+        rfk.block()
         wpas.interface_add("wlan5")
         time.sleep(0.5)
         state = wpas.get_status_field("wpa_state")
         if state != "INTERFACE_DISABLED":
             raise Exception("Unexpected state with rfkill blocked: " + state)
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
         time.sleep(0.5)
         state = wpas.get_status_field("wpa_state")
         if state == "INTERFACE_DISABLED":
             raise Exception("Unexpected state with rfkill unblocked: " + state)
     finally:
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py
index 74bd079..dadf35a 100644
--- a/tests/hwsim/test_sae.py
+++ b/tests/hwsim/test_sae.py
@@ -1,9 +1,11 @@
 # Test cases for SAE
-# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import binascii
+import os
 import time
 import subprocess
 import logging
@@ -11,9 +13,13 @@
 
 import hwsim_utils
 import hostapd
+from utils import HwsimSkip
+from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
 
 def test_sae(dev, apdev):
     """SAE with default group"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
@@ -35,6 +41,8 @@
 
 def test_sae_pmksa_caching(dev, apdev):
     """SAE and PMKSA caching"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
@@ -43,7 +51,11 @@
     dev[0].request("SET sae_groups ")
     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
                    scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].request("RECONNECT")
     dev[0].wait_connected(timeout=15, error="Reconnect timed out")
     if dev[0].get_status_field('sae_group') is not None:
@@ -51,6 +63,8 @@
 
 def test_sae_pmksa_caching_disabled(dev, apdev):
     """SAE and PMKSA caching disabled"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
@@ -60,7 +74,11 @@
     dev[0].request("SET sae_groups ")
     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
                    scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
     dev[0].request("RECONNECT")
     dev[0].wait_connected(timeout=15, error="Reconnect timed out")
     if dev[0].get_status_field('sae_group') != '19':
@@ -68,6 +86,8 @@
 
 def test_sae_groups(dev, apdev):
     """SAE with all supported groups"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     # This would be the full list of supported groups, but groups 14-16
     # (2048-4096 bit MODP) are a bit too slow on some VMs and can result in
     # hitting mac80211 authentication timeout, so skip them for now.
@@ -91,6 +111,8 @@
 
 def test_sae_group_nego(dev, apdev):
     """SAE group negotiation"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae-group-nego",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
@@ -105,6 +127,8 @@
 
 def test_sae_anti_clogging(dev, apdev):
     """SAE anti clogging"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['sae_anti_clogging_threshold'] = '1'
@@ -124,6 +148,8 @@
 
 def test_sae_forced_anti_clogging(dev, apdev):
     """SAE anti clogging (forced)"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
     params['sae_anti_clogging_threshold'] = '0'
@@ -136,6 +162,8 @@
 
 def test_sae_mixed(dev, apdev):
     """Mixed SAE and non-SAE network"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
     params['sae_anti_clogging_threshold'] = '0'
@@ -149,6 +177,8 @@
 
 def test_sae_missing_password(dev, apdev):
     """SAE and missing password"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
@@ -161,3 +191,123 @@
     ev = dev[0].wait_event(['CTRL-EVENT-SSID-TEMP-DISABLED'], timeout=10)
     if ev is None:
         raise Exception("Invalid network not temporarily disabled")
+
+
+def test_sae_key_lifetime_in_memory(dev, apdev, params):
+    """SAE and key lifetime in memory"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
+    password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
+    p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
+    p['wpa_key_mgmt'] = 'SAE'
+    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+
+    pid = find_wpas_process(dev[0])
+
+    dev[0].request("SET sae_groups ")
+    id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
+                        scan_freq="2412")
+
+    time.sleep(1)
+    buf = read_process_memory(pid, password)
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    dev[0].relog()
+    sae_k = None
+    sae_keyseed = None
+    sae_kck = None
+    pmk = None
+    ptk = None
+    gtk = None
+    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
+        for l in f.readlines():
+            if "SAE: k - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                sae_k = binascii.unhexlify(val)
+            if "SAE: keyseed - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                sae_keyseed = binascii.unhexlify(val)
+            if "SAE: KCK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                sae_kck = binascii.unhexlify(val)
+            if "SAE: PMK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                pmk = binascii.unhexlify(val)
+            if "WPA: PTK - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                ptk = binascii.unhexlify(val)
+            if "WPA: Group Key - hexdump" in l:
+                val = l.strip().split(':')[3].replace(' ', '')
+                gtk = binascii.unhexlify(val)
+    if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
+        raise Exception("Could not find keys from debug log")
+    if len(gtk) != 16:
+        raise Exception("Unexpected GTK length")
+
+    kck = ptk[0:16]
+    kek = ptk[16:32]
+    tk = ptk[32:48]
+
+    fname = os.path.join(params['logdir'],
+                         'sae_key_lifetime_in_memory.memctx-')
+
+    logger.info("Checking keys in memory while associated")
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    if password not in buf:
+        raise HwsimSkip("Password not found while associated")
+    if pmk not in buf:
+        raise HwsimSkip("PMK not found while associated")
+    if kck not in buf:
+        raise Exception("KCK not found while associated")
+    if kek not in buf:
+        raise Exception("KEK not found while associated")
+    if tk in buf:
+        raise Exception("TK found from memory")
+    if gtk in buf:
+        raise Exception("GTK found from memory")
+    verify_not_present(buf, sae_k, fname, "SAE(k)")
+    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
+    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
+
+    logger.info("Checking keys in memory after disassociation")
+    buf = read_process_memory(pid, password)
+
+    # Note: Password is still present in network configuration
+    # Note: PMK is in PMKSA cache
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+    verify_not_present(buf, sae_k, fname, "SAE(k)")
+    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
+    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
+
+    dev[0].request("PMKSA_FLUSH")
+    logger.info("Checking keys in memory after PMKSA cache flush")
+    buf = read_process_memory(pid, password)
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    verify_not_present(buf, pmk, fname, "PMK")
+
+    dev[0].request("REMOVE_NETWORK all")
+
+    logger.info("Checking keys in memory after network profile removal")
+    buf = read_process_memory(pid, password)
+
+    get_key_locations(buf, password, "Password")
+    get_key_locations(buf, pmk, "PMK")
+    verify_not_present(buf, password, fname, "password")
+    verify_not_present(buf, pmk, fname, "PMK")
+    verify_not_present(buf, kck, fname, "KCK")
+    verify_not_present(buf, kek, fname, "KEK")
+    verify_not_present(buf, tk, fname, "TK")
+    verify_not_present(buf, gtk, fname, "GTK")
+    verify_not_present(buf, sae_k, fname, "SAE(k)")
+    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
+    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
diff --git a/tests/hwsim/test_scan.py b/tests/hwsim/test_scan.py
index 4939903..914eb41 100644
--- a/tests/hwsim/test_scan.py
+++ b/tests/hwsim/test_scan.py
@@ -1,5 +1,5 @@
 # Scanning tests
-# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -12,6 +12,8 @@
 
 import hostapd
 from wpasupplicant import WpaSupplicant
+from utils import HwsimSkip
+from tshark import run_tshark
 
 def check_scan(dev, params, other_started=False, test_busy=False):
     if not other_started:
@@ -112,7 +114,7 @@
     """Avoid operations during externally triggered scan"""
     hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
-    subprocess.call(['sudo', 'iw', dev[0].ifname, 'scan', 'trigger'])
+    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger'])
     check_scan(dev[0], "use_id=1", other_started=True)
 
 def test_scan_bss_expiration_count(dev, apdev):
@@ -332,8 +334,11 @@
                    wait_connect=False)
     dev[0].dump_monitor()
     # Clear cfg80211 BSS table.
-    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger',
-                     'freq', '2457', 'flush'])
+    try:
+        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
+                               'freq', '2457', 'flush'])
+    except subprocess.CalledProcessError, e:
+        raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
         raise Exception("External flush scan timed out")
@@ -360,8 +365,11 @@
     dev[0].dump_monitor()
     hapd.disable()
     # Clear cfg80211 BSS table.
-    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger',
-                     'freq', '2457', 'flush'])
+    try:
+        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
+                               'freq', '2457', 'flush'])
+    except subprocess.CalledProcessError, e:
+        raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
         raise Exception("External flush scan timed out")
@@ -396,8 +404,11 @@
                    auth_alg="SHARED", scan_freq="2412", wait_connect=False)
     dev[0].dump_monitor()
     # Clear cfg80211 BSS table.
-    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger',
-                     'freq', '2457', 'flush'])
+    try:
+        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
+                               'freq', '2457', 'flush'])
+    except subprocess.CalledProcessError, e:
+        raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
         raise Exception("External flush scan timed out")
@@ -427,8 +438,16 @@
     if "test-scan" in dev[0].request("SCAN_RESULTS"):
         raise Exception("BSS unexpectedly found in scan")
 
-    check_scan(dev[0], "scan_id=%d,%d,%d freq=2412 use_id=1" % (id1, id2, id3))
-    if "test-scan" not in dev[0].request("SCAN_RESULTS"):
+    # Allow multiple attempts to be more robust under heavy CPU load that can
+    # result in Probe Response frames getting sent only after the station has
+    # already stopped waiting for the response on the channel.
+    found = False
+    for i in range(10):
+        check_scan(dev[0], "scan_id=%d,%d,%d freq=2412 use_id=1" % (id1, id2, id3))
+        if "test-scan" in dev[0].request("SCAN_RESULTS"):
+            found = True
+            break
+    if not found:
         raise Exception("BSS not found in scan")
 
     if "FAIL" not in dev[0].request("SCAN scan_id=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17"):
@@ -661,3 +680,100 @@
     dev[0].wait_connected(timeout=30)
     dev[0].request("REMOVE_NETWORK all")
     hapd.disable()
+
+def test_scan_random_mac(dev, apdev, params):
+    """Random MAC address in scans"""
+    try:
+        _test_scan_random_mac(dev, apdev, params)
+    finally:
+        dev[0].request("MAC_RAND_SCAN all enable=0")
+
+def _test_scan_random_mac(dev, apdev, params):
+    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    bssid = apdev[0]['bssid']
+
+    tests = [ "",
+              "addr=foo",
+              "mask=foo",
+              "enable=1",
+              "all enable=1 mask=00:11:22:33:44:55",
+              "all enable=1 addr=00:11:22:33:44:55",
+              "all enable=1 addr=01:11:22:33:44:55 mask=ff:ff:ff:ff:ff:ff",
+              "all enable=1 addr=00:11:22:33:44:55 mask=fe:ff:ff:ff:ff:ff",
+              "enable=2 scan sched pno all",
+              "pno enable=1",
+              "all enable=2",
+              "foo" ]
+    for args in tests:
+        if "FAIL" not in dev[0].request("MAC_RAND_SCAN " + args):
+            raise Exception("Invalid MAC_RAND_SCAN accepted: " + args)
+
+    if dev[0].get_driver_status_field('capa.mac_addr_rand_scan_supported') != '1':
+        raise HwsimSkip("Driver does not support random MAC address for scanning")
+
+    tests = [ "all enable=1",
+              "all enable=1 addr=f2:11:22:33:44:55 mask=ff:ff:ff:ff:ff:ff",
+              "all enable=1 addr=f2:11:33:00:00:00 mask=ff:ff:ff:00:00:00" ]
+    for args in tests:
+        dev[0].request("MAC_RAND_SCAN " + args)
+        dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan.fc.type_subtype == 4", ["wlan.ta" ])
+    if out is not None:
+        addr = out.splitlines()
+        logger.info("Probe Request frames seen from: " + str(addr))
+        if dev[0].own_addr() in addr:
+            raise Exception("Real address used to transmit Probe Request frame")
+        if "f2:11:22:33:44:55" not in addr:
+            raise Exception("Fully configured random address not seen")
+        found = False
+        for a in addr:
+            if a.startswith('f2:11:33'):
+                found = True
+                break
+        if not found:
+            raise Exception("Fixed OUI random address not seen")
+
+def test_scan_trigger_failure(dev, apdev):
+    """Scan trigger to the driver failing"""
+    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    bssid = apdev[0]['bssid']
+
+    if "OK" not in dev[0].request("SET test_failure 1"):
+        raise Exception("Failed to set test_failure")
+
+    if "OK" not in dev[0].request("SCAN"):
+        raise Exception("SCAN command failed")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
+    if ev is None:
+        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
+    if "retry=1" in ev:
+        raise Exception("Unexpected scan retry indicated")
+    if dev[0].get_status_field('wpa_state') == "SCANNING":
+        raise Exception("wpa_state SCANNING not cleared")
+
+    id = dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412",
+                        only_add_network=True)
+    dev[0].select_network(id)
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
+    if ev is None:
+        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
+    if "retry=1" not in ev:
+        raise Exception("No scan retry indicated for connection")
+    if dev[0].get_status_field('wpa_state') == "SCANNING":
+        raise Exception("wpa_state SCANNING not cleared")
+    dev[0].request("SET test_failure 0")
+    dev[0].wait_connected()
+
+    dev[0].request("SET test_failure 1")
+    if "OK" not in dev[0].request("SCAN"):
+        raise Exception("SCAN command failed")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
+    if ev is None:
+        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
+    if "retry=1" in ev:
+        raise Exception("Unexpected scan retry indicated")
+    if dev[0].get_status_field('wpa_state') != "COMPLETED":
+        raise Exception("wpa_state COMPLETED not restored")
+    dev[0].request("SET test_failure 0")
diff --git a/tests/hwsim/test_sta_dynamic.py b/tests/hwsim/test_sta_dynamic.py
index 15fb0a0..49c1ae4 100644
--- a/tests/hwsim/test_sta_dynamic.py
+++ b/tests/hwsim/test_sta_dynamic.py
@@ -41,7 +41,7 @@
     wpas.request("ENABLE_NETWORK " + str(id) + " no-connect")
     wpas.request("SCAN")
     time.sleep(0.5)
-    subprocess.call(['sudo', 'iw', wpas.ifname, 'connect', 'test', '2412'])
+    subprocess.call(['iw', wpas.ifname, 'connect', 'test', '2412'])
     wpas.wait_connected(timeout=10)
     wpas.request("SCAN")
     wpas.wait_connected(timeout=5)
@@ -65,16 +65,15 @@
     id = wpas.connect("", key_mgmt="NONE", bssid=bssid,
                       only_add_network=True)
     wpas.request("ENABLE_NETWORK " + str(id) + " no-connect")
-    subprocess.call(['sudo', 'iw', wpas.ifname, 'scan', 'trigger',
-                     'freq', '2412'])
+    subprocess.call(['iw', wpas.ifname, 'scan', 'trigger', 'freq', '2412'])
     time.sleep(1)
-    subprocess.call(['sudo', 'iw', wpas.ifname, 'connect', 'test', '2412'])
+    subprocess.call(['iw', wpas.ifname, 'connect', 'test', '2412'])
     wpas.wait_connected(timeout=10)
 
     wpas.request("SET disallow_aps bssid " + bssid)
     wpas.wait_disconnected(timeout=10)
 
-    subprocess.call(['sudo', 'iw', wpas.ifname, 'connect', 'test', '2412'])
+    subprocess.call(['iw', wpas.ifname, 'connect', 'test', '2412'])
     ev = wpas.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected connection reported")
@@ -121,11 +120,11 @@
     wpas.interface_add("wlan5")
     wpas.connect("sta-dynamic", psk="12345678", scan_freq="2412")
     hwsim_utils.test_connectivity(wpas, hapd)
-    subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'down'])
+    subprocess.call(['ifconfig', wpas.ifname, 'down'])
     wpas.wait_disconnected(timeout=10)
     if wpas.get_status_field("wpa_state") != "INTERFACE_DISABLED":
         raise Exception("Unexpected wpa_state")
-    subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'up'])
+    subprocess.call(['ifconfig', wpas.ifname, 'up'])
     wpas.wait_connected(timeout=15, error="Reconnection not reported")
     hwsim_utils.test_connectivity(wpas, hapd)
 
@@ -139,16 +138,16 @@
     wpas.interface_add("wlan5")
     wpas.connect("sta-dynamic", psk="12345678", scan_freq="2412")
     hwsim_utils.test_connectivity(wpas, hapd)
-    subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'down'])
+    subprocess.call(['ifconfig', wpas.ifname, 'down'])
     wpas.wait_disconnected(timeout=10)
     if wpas.get_status_field("wpa_state") != "INTERFACE_DISABLED":
         raise Exception("Unexpected wpa_state")
     prev_addr = wpas.p2p_interface_addr()
     new_addr = '02:11:22:33:44:55'
     try:
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', wpas.ifname,
+        subprocess.call(['ip', 'link', 'set', 'dev', wpas.ifname,
                          'address', new_addr])
-        subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'up'])
+        subprocess.call(['ifconfig', wpas.ifname, 'up'])
         wpas.wait_connected(timeout=15, error="Reconnection not reported")
         if wpas.get_driver_status_field('addr') != new_addr:
             raise Exception("Address change not reported")
@@ -157,10 +156,10 @@
         if sta['addr'] != new_addr:
             raise Exception("STA association with new address not found")
     finally:
-        subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'down'])
-        subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', wpas.ifname,
+        subprocess.call(['ifconfig', wpas.ifname, 'down'])
+        subprocess.call(['ip', 'link', 'set', 'dev', wpas.ifname,
                          'address', prev_addr])
-        subprocess.call(['sudo', 'ifconfig', wpas.ifname, 'up'])
+        subprocess.call(['ifconfig', wpas.ifname, 'up'])
 
 def test_sta_dynamic_random_mac_addr(dev, apdev):
     """Dynamically added wpa_supplicant interface and random MAC address"""
diff --git a/tests/hwsim/test_suite_b.py b/tests/hwsim/test_suite_b.py
index 77d0ebb..1fabe3e 100644
--- a/tests/hwsim/test_suite_b.py
+++ b/tests/hwsim/test_suite_b.py
@@ -1,5 +1,5 @@
 # Suite B tests
-# Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -9,21 +9,49 @@
 logger = logging.getLogger()
 
 import hostapd
+from utils import HwsimSkip
 
 def test_suite_b(dev, apdev):
-    """WPA2-PSK/GCMP connection"""
+    """WPA2-PSK/GCMP connection at Suite B 128-bit level"""
     if "GCMP" not in dev[0].get_capability("pairwise"):
-        return "skip"
-    params = hostapd.wpa2_eap_params(ssid="test-suite-b")
-    params["wpa_key_mgmt"] = "WPA-EAP-SUITE-B"
-    params['rsn_pairwise'] = "GCMP"
+        raise HwsimSkip("GCMP not supported")
+    if "BIP-GMAC-128" not in dev[0].get_capability("group_mgmt"):
+        raise HwsimSkip("BIP-GMAC-128 not supported")
+    if "WPA-EAP-SUITE-B" not in dev[0].get_capability("key_mgmt"):
+        raise HwsimSkip("WPA-EAP-SUITE-B not supported")
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("TLS library not supported for Suite B: " + tls);
+    if "build=OpenSSL 1.0.2" not in tls or "run=OpenSSL 1.0.2" not in tls:
+        raise HwsimSkip("OpenSSL version not supported for Suite B: " + tls)
+
+    dev[0].flush_scan_cache()
+    params = { "ssid": "test-suite-b",
+               "wpa": "2",
+               "wpa_key_mgmt": "WPA-EAP-SUITE-B",
+               "rsn_pairwise": "GCMP",
+               "group_mgmt_cipher": "BIP-GMAC-128",
+               "ieee80211w": "2",
+               "ieee8021x": "1",
+               "openssl_ciphers": "SUITEB128",
+               #"dh_file": "auth_serv/dh.conf",
+               "eap_server": "1",
+               "eap_user_file": "auth_serv/eap_user.conf",
+               "ca_cert": "auth_serv/ec-ca.pem",
+               "server_cert": "auth_serv/ec-server.pem",
+               "private_key": "auth_serv/ec-server.key" }
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    # TODO: Force Suite B configuration for TLS
-    dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B",
-                   eap="TLS", identity="tls user", ca_cert="auth_serv/ca.pem",
-                   client_cert="auth_serv/user.pem",
-                   private_key="auth_serv/user.key",
+
+    dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B", ieee80211w="2",
+                   openssl_ciphers="SUITEB128",
+                   eap="TLS", identity="tls user",
+                   ca_cert="auth_serv/ec-ca.pem",
+                   client_cert="auth_serv/ec-user.pem",
+                   private_key="auth_serv/ec-user.key",
                    pairwise="GCMP", group="GCMP", scan_freq="2412")
+    tls_cipher = dev[0].get_status_field("EAP TLS cipher")
+    if tls_cipher != "ECDHE-ECDSA-AES128-GCM-SHA256":
+        raise Exception("Unexpected TLS cipher: " + tls_cipher)
 
     bss = dev[0].get_bss(apdev[0]['bssid'])
     if 'flags' not in bss:
@@ -41,3 +69,62 @@
         raise Exception("Roaming with the AP timed out")
     if "CTRL-EVENT-EAP-STARTED" in ev:
         raise Exception("Unexpected EAP exchange")
+
+def test_suite_b_192(dev, apdev):
+    """WPA2-PSK/GCMP-256 connection at Suite B 192-bit level"""
+    if "GCMP-256" not in dev[0].get_capability("pairwise"):
+        raise HwsimSkip("GCMP-256 not supported")
+    if "BIP-GMAC-256" not in dev[0].get_capability("group_mgmt"):
+        raise HwsimSkip("BIP-GMAC-256 not supported")
+    if "WPA-EAP-SUITE-B-192" not in dev[0].get_capability("key_mgmt"):
+        raise HwsimSkip("WPA-EAP-SUITE-B-192 not supported")
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("TLS library not supported for Suite B: " + tls);
+    if "build=OpenSSL 1.0.2" not in tls or "run=OpenSSL 1.0.2" not in tls:
+        raise HwsimSkip("OpenSSL version not supported for Suite B: " + tls)
+
+    dev[0].flush_scan_cache()
+    params = { "ssid": "test-suite-b",
+               "wpa": "2",
+               "wpa_key_mgmt": "WPA-EAP-SUITE-B-192",
+               "rsn_pairwise": "GCMP-256",
+               "group_mgmt_cipher": "BIP-GMAC-256",
+               "ieee80211w": "2",
+               "ieee8021x": "1",
+               "openssl_ciphers": "SUITEB192",
+               "eap_server": "1",
+               "eap_user_file": "auth_serv/eap_user.conf",
+               "ca_cert": "auth_serv/ec2-ca.pem",
+               "server_cert": "auth_serv/ec2-server.pem",
+               "private_key": "auth_serv/ec2-server.key" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
+                   ieee80211w="2",
+                   openssl_ciphers="SUITEB192",
+                   eap="TLS", identity="tls user",
+                   ca_cert="auth_serv/ec2-ca.pem",
+                   client_cert="auth_serv/ec2-user.pem",
+                   private_key="auth_serv/ec2-user.key",
+                   pairwise="GCMP-256", group="GCMP-256", scan_freq="2412")
+    tls_cipher = dev[0].get_status_field("EAP TLS cipher")
+    if tls_cipher != "ECDHE-ECDSA-AES256-GCM-SHA384":
+        raise Exception("Unexpected TLS cipher: " + tls_cipher)
+
+    bss = dev[0].get_bss(apdev[0]['bssid'])
+    if 'flags' not in bss:
+        raise Exception("Could not get BSS flags from BSS table")
+    if "[WPA2-EAP-SUITE-B-192-GCMP-256]" not in bss['flags']:
+        raise Exception("Unexpected BSS flags: " + bss['flags'])
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=20)
+    dev[0].dump_monitor()
+    dev[0].request("RECONNECT")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+                            "CTRL-EVENT-CONNECTED"], timeout=20)
+    if ev is None:
+        raise Exception("Roaming with the AP timed out")
+    if "CTRL-EVENT-EAP-STARTED" in ev:
+        raise Exception("Unexpected EAP exchange")
diff --git a/tests/hwsim/test_tnc.py b/tests/hwsim/test_tnc.py
index 003d0f8..fc23bd7 100644
--- a/tests/hwsim/test_tnc.py
+++ b/tests/hwsim/test_tnc.py
@@ -8,7 +8,8 @@
 import os.path
 
 import hostapd
-from test_ap_eap import int_eap_server_params
+from utils import HwsimSkip
+from test_ap_eap import int_eap_server_params, check_eap_capa
 
 def test_tnc_peap_soh(dev, apdev):
     """TNC PEAP-SoH"""
@@ -47,8 +48,7 @@
     hostapd.add_ap(apdev[0]['ifname'], params)
 
     if not os.path.exists("tnc/libhostap_imc.so"):
-        logger.info("No IMC installed - skip")
-        return "skip"
+        raise HwsimSkip("No IMC installed")
 
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
                    eap="TTLS", identity="DOMAIN\mschapv2 user",
@@ -58,8 +58,28 @@
                    wait_connect=False)
     dev[0].wait_connected(timeout=10)
 
+def test_tnc_ttls_fragmentation(dev, apdev):
+    """TNC TTLS with fragmentation"""
+    params = int_eap_server_params()
+    params["tnc"] = "1"
+    params["fragment_size"] = "150"
+    hostapd.add_ap(apdev[0]['ifname'], params)
+
+    if not os.path.exists("tnc/libhostap_imc.so"):
+        raise HwsimSkip("No IMC installed")
+
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                   eap="TTLS", identity="DOMAIN\mschapv2 user",
+                   anonymous_identity="ttls", password="password",
+                   phase2="auth=MSCHAPV2",
+                   ca_cert="auth_serv/ca.pem",
+                   fragment_size="150",
+                   wait_connect=False)
+    dev[0].wait_connected(timeout=10)
+
 def test_tnc_fast(dev, apdev):
     """TNC FAST"""
+    check_eap_capa(dev[0], "FAST")
     params = int_eap_server_params()
     params["tnc"] = "1"
     params["pac_opaque_encr_key"] ="000102030405060708090a0b0c0d0e00"
@@ -69,8 +89,7 @@
     hostapd.add_ap(apdev[0]['ifname'], params)
 
     if not os.path.exists("tnc/libhostap_imc.so"):
-        logger.info("No IMC installed - skip")
-        return "skip"
+        raise HwsimSkip("No IMC installed")
 
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
                    eap="FAST", identity="user",
diff --git a/tests/hwsim/test_wext.py b/tests/hwsim/test_wext.py
index 1efb5c9..9fef54b 100644
--- a/tests/hwsim/test_wext.py
+++ b/tests/hwsim/test_wext.py
@@ -1,5 +1,5 @@
 # Deprecated WEXT driver interface in wpa_supplicant
-# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -7,31 +7,28 @@
 import logging
 logger = logging.getLogger()
 import os
-import subprocess
 
 import hostapd
 import hwsim_utils
 from wpasupplicant import WpaSupplicant
-from test_rfkill import get_rfkill_id
+from utils import HwsimSkip
+from test_rfkill import get_rfkill
 
 def get_wext_interface():
     if not os.path.exists("/proc/net/wireless"):
-        logger.info("WEXT support not included in the kernel")
-        return
+        raise HwsimSkip("WEXT support not included in the kernel")
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     try:
         wpas.interface_add("wlan5", driver="wext")
     except Exception, e:
-        logger.info("WEXT driver support not included in wpa_supplicant")
-        return
+        wpas.close_ctrl()
+        raise HwsimSkip("WEXT driver support not included in wpa_supplicant")
     return wpas
 
 def test_wext_open(dev, apdev):
     """WEXT driver interface with open network"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     params = { "ssid": "wext-open" }
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
@@ -42,8 +39,6 @@
 def test_wext_wpa2_psk(dev, apdev):
     """WEXT driver interface with WPA2-PSK"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     params = hostapd.wpa2_params(ssid="wext-wpa2-psk", passphrase="12345678")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
@@ -60,14 +55,13 @@
 def test_wext_wpa_psk(dev, apdev):
     """WEXT driver interface with WPA-PSK"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     params = hostapd.wpa_params(ssid="wext-wpa-psk", passphrase="12345678")
     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (hapd.get_driver_status_field("phyname"), apdev[0]['ifname'])
     if not os.path.exists(testfile):
-        return "skip"
+        wpas.close_ctrl()
+        raise HwsimSkip("tkip_mic_test not supported in mac80211")
 
     wpas.connect("wext-wpa-psk", psk="12345678")
     hwsim_utils.test_connectivity(wpas, hapd)
@@ -88,8 +82,6 @@
 def test_wext_pmksa_cache(dev, apdev):
     """PMKSA caching with WEXT"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
     hostapd.add_ap(apdev[0]['ifname'], params)
@@ -156,8 +148,6 @@
 def test_wext_wep_open_auth(dev, apdev):
     """WEP Open System authentication"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     hapd = hostapd.add_ap(apdev[0]['ifname'],
                           { "ssid": "wep-open",
@@ -171,8 +161,6 @@
 def test_wext_wep_shared_key_auth(dev, apdev):
     """WEP Shared Key authentication"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     hapd = hostapd.add_ap(apdev[0]['ifname'],
                           { "ssid": "wep-shared-key",
@@ -189,8 +177,6 @@
 def test_wext_pmf(dev, apdev):
     """WEXT driver interface with WPA2-PSK and PMF"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     params = hostapd.wpa2_params(ssid="wext-wpa2-psk", passphrase="12345678")
     params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
@@ -209,8 +195,6 @@
 def test_wext_scan_hidden(dev, apdev):
     """WEXT with hidden SSID"""
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan",
                                                 "ignore_broadcast_ssid": "1" })
@@ -244,27 +228,23 @@
     """WEXT and rfkill block/unblock"""
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
-    id = get_rfkill_id(wpas)
-    if id is None:
-        return "skip"
+    rfk = get_rfkill(wpas)
     wpas.interface_remove("wlan5")
 
     wpas = get_wext_interface()
-    if not wpas:
-        return "skip"
 
     hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
     wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
     try:
         logger.info("rfkill block")
-        subprocess.call(['rfkill', 'block', id])
+        rfk.block()
         wpas.wait_disconnected(timeout=10,
                                error="Missing disconnection event on rfkill block")
 
         logger.info("rfkill unblock")
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
         wpas.wait_connected(timeout=20,
                             error="Missing connection event on rfkill unblock")
         hwsim_utils.test_connectivity(wpas, hapd)
     finally:
-        subprocess.call(['rfkill', 'unblock', id])
+        rfk.unblock()
diff --git a/tests/hwsim/test_wnm.py b/tests/hwsim/test_wnm.py
index 08a4085..d0f904c 100644
--- a/tests/hwsim/test_wnm.py
+++ b/tests/hwsim/test_wnm.py
@@ -97,6 +97,7 @@
     sta = hapd.get_sta(addr)
     if "[WNM_SLEEP_MODE]" in sta['flags']:
         raise Exception("Station unexpectedly in WNM-Sleep Mode")
+
     logger.info("Going to WNM Sleep Mode")
     extra = ""
     if interval is not None:
@@ -105,15 +106,26 @@
         extra += " tfs_req=" + tfs_req
     if "OK" not in dev.request("WNM_SLEEP enter" + extra):
         raise Exception("WNM_SLEEP failed")
-    time.sleep(0.5)
-    sta = hapd.get_sta(addr)
-    if "[WNM_SLEEP_MODE]" not in sta['flags']:
+    ok = False
+    for i in range(20):
+        time.sleep(0.1)
+        sta = hapd.get_sta(addr)
+        if "[WNM_SLEEP_MODE]" in sta['flags']:
+            ok = True
+            break
+    if not ok:
         raise Exception("Station failed to enter WNM-Sleep Mode")
+
     logger.info("Waking up from WNM Sleep Mode")
+    ok = False
     dev.request("WNM_SLEEP exit")
-    time.sleep(0.5)
-    sta = hapd.get_sta(addr)
-    if "[WNM_SLEEP_MODE]" in sta['flags']:
+    for i in range(20):
+        time.sleep(0.1)
+        sta = hapd.get_sta(addr)
+        if "[WNM_SLEEP_MODE]" not in sta['flags']:
+            ok = True
+            break
+    if not ok:
         raise Exception("Station failed to exit WNM-Sleep Mode")
 
 def test_wnm_sleep_mode_open(dev, apdev):
@@ -127,6 +139,9 @@
     hapd = hostapd.Hostapd(apdev[0]['ifname'])
 
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
     check_wnm_sleep_mode_enter_exit(hapd, dev[0], interval=100)
     check_wnm_sleep_mode_enter_exit(hapd, dev[0], tfs_req="5b17010001130e110000071122334455661122334455661234")
@@ -149,6 +164,9 @@
     hapd = hostapd.Hostapd(apdev[0]['ifname'])
 
     dev[0].connect("test-wnm-rsn", psk="12345678", scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
 
 def test_wnm_sleep_mode_rsn_pmf(dev, apdev):
@@ -168,6 +186,9 @@
 
     dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2",
                    key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
 
 MGMT_SUBTYPE_ACTION = 13
diff --git a/tests/hwsim/test_wpas_ap.py b/tests/hwsim/test_wpas_ap.py
index c9ee8b8..53de399 100644
--- a/tests/hwsim/test_wpas_ap.py
+++ b/tests/hwsim/test_wpas_ap.py
@@ -9,6 +9,8 @@
 logger = logging.getLogger()
 
 import hwsim_utils
+from utils import HwsimSkip
+from test_p2p_channel import set_country
 
 def wait_ap_ready(dev):
     ev = dev.wait_event(["CTRL-EVENT-CONNECTED"])
@@ -274,3 +276,61 @@
     dev[0].request("WPS_CANCEL")
     dev[1].request("WPS_CANCEL")
     dev[2].request("WPS_CANCEL")
+
+def test_wpas_ap_dfs(dev):
+    """wpa_supplicant AP mode - DFS"""
+    try:
+        _test_wpas_ap_dfs(dev)
+    finally:
+        set_country("00")
+        dev[0].request("SET country 00")
+        dev[1].flush_scan_cache()
+
+def _test_wpas_ap_dfs(dev):
+    set_country("US")
+    dev[0].request("SET country US")
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-dfs")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "5260")
+    dev[0].set_network(id, "scan_freq", "5260")
+    dev[0].select_network(id)
+
+    ev = dev[0].wait_event(["DFS-CAC-START"])
+    if ev is None:
+        # For now, assume DFS is not supported by all kernel builds.
+        raise HwsimSkip("CAC did not start - assume not supported")
+
+    ev = dev[0].wait_event(["DFS-CAC-COMPLETED"], timeout=70)
+    if ev is None:
+        raise Exception("CAC did not complete")
+    if "success=1" not in ev:
+        raise Exception("CAC failed")
+    if "freq=5260" not in ev:
+        raise Exception("Unexpected DFS freq result")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"])
+    if ev is None:
+        raise Exception("AP failed to start")
+
+    dev[1].connect("wpas-ap-dfs", key_mgmt="NONE")
+
+def test_wpas_ap_disable(dev):
+    """wpa_supplicant AP mode - DISABLE_NETWORK"""
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].select_network(id)
+
+    ev = dev[0].wait_event(["AP-ENABLED"])
+    if ev is None:
+        raise Exception("AP-ENABLED event not seen")
+    wait_ap_ready(dev[0])
+    dev[0].request("DISABLE_NETWORK %d" % id)
+    ev = dev[0].wait_event(["AP-DISABLED"])
+    if ev is None:
+        raise Exception("AP-DISABLED event not seen")
+    dev[0].wait_disconnected()
diff --git a/tests/hwsim/test_wpas_config.py b/tests/hwsim/test_wpas_config.py
index 223b428..1dd839c 100644
--- a/tests/hwsim/test_wpas_config.py
+++ b/tests/hwsim/test_wpas_config.py
@@ -7,7 +7,6 @@
 import logging
 logger = logging.getLogger()
 import os
-import subprocess
 
 from wpasupplicant import WpaSupplicant
 
@@ -34,7 +33,7 @@
     """wpa_supplicant config file parsing/writing"""
     config = "/tmp/test_wpas_config_file.conf"
     if os.path.exists(config):
-        subprocess.call(['sudo', 'rm', config])
+        os.remove(config)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     try:
@@ -119,9 +118,9 @@
         if "OK" in wpas.global_request("SAVE_CONFIG"):
             raise Exception("SAVE_CONFIG (global) succeeded unexpectedly")
 
-        # symlink config file to itself to break writing
-        subprocess.call(['rm', config])
-        subprocess.call(['ln', '-s', config, config])
+        # replace the config file with a directory to break writing/renaming
+        os.remove(config)
+        os.mkdir(config)
         wpas.request("SET update_config 1")
         if "OK" in wpas.request("SAVE_CONFIG"):
             raise Exception("SAVE_CONFIG succeeded unexpectedly")
@@ -129,4 +128,15 @@
             raise Exception("SAVE_CONFIG (global) succeeded unexpectedly")
 
     finally:
-        subprocess.call(['sudo', 'rm', config])
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
diff --git a/tests/hwsim/test_wpas_ctrl.py b/tests/hwsim/test_wpas_ctrl.py
index dbb2e8d..1c84eb0 100644
--- a/tests/hwsim/test_wpas_ctrl.py
+++ b/tests/hwsim/test_wpas_ctrl.py
@@ -10,7 +10,9 @@
 import time
 
 import hostapd
+import hwsim_utils
 from wpasupplicant import WpaSupplicant
+from utils import alloc_fail
 
 def test_wpas_ctrl_network(dev):
     """wpa_supplicant ctrl_iface network set/get"""
@@ -201,6 +203,32 @@
     if "FAIL" not in dev[0].request('BSSID ' + str(id)):
         raise Exception("Unexpected BSSID success")
 
+    tests = [ "02:11:22:33:44:55",
+              "02:11:22:33:44:55 02:ae:be:ce:53:77",
+              "02:11:22:33:44:55/ff:00:ff:00:ff:00",
+              "02:11:22:33:44:55/ff:00:ff:00:ff:00 f2:99:88:77:66:55",
+              "f2:99:88:77:66:55 02:11:22:33:44:55/ff:00:ff:00:ff:00",
+              "f2:99:88:77:66:55 02:11:22:33:44:55/ff:00:ff:00:ff:00 12:34:56:78:90:ab",
+              "02:11:22:33:44:55/ff:ff:ff:00:00:00 02:ae:be:ce:53:77/00:00:00:00:00:ff" ]
+    for val in tests:
+        dev[0].set_network(id, "bssid_blacklist", val)
+        res = dev[0].get_network(id, "bssid_blacklist")
+        if res != val:
+            raise Exception("Unexpected bssid_blacklist value: %s != %s" % (res, val))
+        dev[0].set_network(id, "bssid_whitelist", val)
+        res = dev[0].get_network(id, "bssid_whitelist")
+        if res != val:
+            raise Exception("Unexpected bssid_whitelist value: %s != %s" % (res, val))
+
+    tests = [ "foo",
+              "00:11:22:33:44:5",
+              "00:11:22:33:44:55q",
+              "00:11:22:33:44:55/",
+              "00:11:22:33:44:55/66:77:88:99:aa:b" ]
+    for val in tests:
+        if "FAIL" not in dev[0].request("SET_NETWORK %d bssid_blacklist %s" % (id, val)):
+            raise Exception("Invalid bssid_blacklist value accepted")
+
 def test_wpas_ctrl_many_networks(dev, apdev):
     """wpa_supplicant ctrl_iface LIST_NETWORKS with huge number of networks"""
     for i in range(1000):
@@ -211,6 +239,10 @@
     res = dev[0].request("LIST_NETWORKS LAST_ID=%d" % (id - 2))
     if str(id) not in res:
         raise Exception("Last added network was not present when using LAST_ID")
+    # This command can take a very long time under valgrind testing on a low
+    # power CPU, so increase the command timeout significantly to avoid issues
+    # with the test case failing and following reset operation timing out.
+    dev[0].request("REMOVE_NETWORK all", timeout=60)
 
 def test_wpas_ctrl_dup_network(dev, apdev):
     """wpa_supplicant ctrl_iface DUP_NETWORK"""
@@ -496,6 +528,18 @@
     if "FAIL" not in dev[0].request("TDLS_DISCOVER 00:11:22:33:44:55"):
         raise Exception("Unexpected success on TDLS_DISCOVER")
 
+def test_wpas_ctrl_tdls_chan_switch(dev):
+    """wpa_supplicant ctrl_iface tdls_chan_switch error cases"""
+    for args in [ '', '00:11:22:33:44:55' ]:
+        if "FAIL" not in dev[0].request("TDLS_CANCEL_CHAN_SWITCH " + args):
+            raise Exception("Unexpected success on invalid TDLS_CANCEL_CHAN_SWITCH: " + args)
+
+    for args in [ '', 'foo ', '00:11:22:33:44:55 ', '00:11:22:33:44:55 q',
+                  '00:11:22:33:44:55 81', '00:11:22:33:44:55 81 1234',
+                  '00:11:22:33:44:55 81 1234 center_freq1=234 center_freq2=345 bandwidth=456 sec_channel_offset=567 ht vht' ]:
+        if "FAIL" not in dev[0].request("TDLS_CHAN_SWITCH " + args):
+            raise Exception("Unexpected success on invalid TDLS_CHAN_SWITCH: " + args)
+
 def test_wpas_ctrl_addr(dev):
     """wpa_supplicant ctrl_iface invalid address"""
     if "FAIL" not in dev[0].request("TDLS_SETUP "):
@@ -669,12 +713,13 @@
 
     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
     hostapd.add_ap(apdev[1]['ifname'], params)
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     dev[0].dump_monitor()
     if "OK" not in dev[0].request("SET disallow_aps bssid 00:11:22:33:44:55 bssid 00:22:33:44:55:66"):
         raise Exception("Failed to set disallow_aps")
     if "OK" not in dev[0].request("SET disallow_aps bssid " + apdev[0]['bssid']):
         raise Exception("Failed to set disallow_aps")
-    ev = dev[0].wait_connected(timeout=15, error="Reassociation timed out")
+    ev = dev[0].wait_connected(timeout=30, error="Reassociation timed out")
     if apdev[1]['bssid'] not in ev:
         raise Exception("Unexpected BSSID")
 
@@ -884,6 +929,12 @@
     if dev[0].request("BLACKLIST") != "":
         raise Exception("Unexpected blacklist contents")
 
+def test_wpas_ctrl_blacklist_oom(dev):
+    """wpa_supplicant ctrl_iface BLACKLIST and out-of-memory"""
+    with alloc_fail(dev[0], 1, "wpa_blacklist_add"):
+        if "FAIL" not in dev[0].request("BLACKLIST aa:bb:cc:dd:ee:ff"):
+            raise Exception("Unexpected success with allocation failure")
+
 def test_wpas_ctrl_log_level(dev):
     """wpa_supplicant ctrl_iface LOG_LEVEL"""
     level = dev[2].request("LOG_LEVEL")
@@ -980,7 +1031,7 @@
         if "init=CORE type=WORLD" not in ev:
             raise Exception("Unexpected event contents: " + ev)
     finally:
-        subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
+        subprocess.call(['iw', 'reg', 'set', '00'])
 
 def test_wpas_ctrl_suspend_resume(dev):
     """wpa_supplicant SUSPEND/RESUME"""
@@ -1029,10 +1080,10 @@
 
     if "p2p_state=IDLE" not in wpas.global_request("STATUS"):
         raise Exception("P2P was disabled")
-    wpas.request("P2P_SET disabled 1")
+    wpas.global_request("P2P_SET disabled 1")
     if "p2p_state=DISABLED" not in wpas.global_request("STATUS"):
         raise Exception("P2P was not disabled")
-    wpas.request("P2P_SET disabled 0")
+    wpas.global_request("P2P_SET disabled 0")
     if "p2p_state=IDLE" not in wpas.global_request("STATUS"):
         raise Exception("P2P was not enabled")
 
@@ -1221,7 +1272,7 @@
     if "OK" not in dev[0].request("VENDOR_ELEM_ADD 1 "):
         raise Exception("VENDOR_ELEM_ADD failed")
     cmds = [ "-1 ",
-             "13 ",
+             "255 ",
              "1",
              "1 123",
              "1 12qq34" ]
@@ -1230,14 +1281,14 @@
             raise Exception("Invalid VENDOR_ELEM_ADD command accepted: " + cmd)
 
     cmds = [ "-1 ",
-             "13 " ]
+             "255 " ]
     for cmd in cmds:
         if "FAIL" not in dev[0].request("VENDOR_ELEM_GET " + cmd):
             raise Exception("Invalid VENDOR_ELEM_GET command accepted: " + cmd)
 
     dev[0].request("VENDOR_ELEM_REMOVE 1 *")
     cmds = [ "-1 ",
-             "13 ",
+             "255 ",
              "1",
              "1",
              "1 123",
@@ -1252,7 +1303,7 @@
     if "OK" not in dev[0].request("VENDOR_ELEM_REMOVE 1 "):
         raise Exception("VENDOR_ELEM_REMOVE failed")
     cmds = [ "-1 ",
-             "13 ",
+             "255 ",
              "1",
              "1 123",
              "1 12qq34",
@@ -1283,3 +1334,56 @@
         raise Exception("Invalid INTERFACE_REMOVE accepted")
     if "FAIL" not in dev[0].global_request("SET foo"):
         raise Exception("Invalid global SET accepted")
+
+def test_wpas_ctrl_dump(dev, apdev):
+    """wpa_supplicant ctrl_iface and DUMP/GET global parameters"""
+    vals = dev[0].get_config()
+    logger.info("Config values from DUMP: " + str(vals))
+    for field in vals:
+        res = dev[0].request("GET " + field)
+        if res == 'FAIL\n':
+            res = "null"
+        if res != vals[field]:
+            print "'{}' != '{}'".format(res, vals[field])
+            raise Exception("Mismatch in config field " + field)
+    if "beacon_int" not in vals:
+        raise Exception("Missing config field")
+
+def test_wpas_ctrl_interface_add(dev, apdev):
+    """wpa_supplicant INTERFACE_ADD/REMOVE with vif creation/removal"""
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+    ifname = "test-" + dev[0].ifname
+    dev[0].interface_add(ifname, create=True)
+    wpas = WpaSupplicant(ifname=ifname)
+    wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(wpas, hapd)
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    dev[0].global_request("INTERFACE_REMOVE " + ifname)
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_wpas_ctrl_interface_add2(dev, apdev):
+    """wpa_supplicant INTERFACE_ADD/REMOVE with vif without creation/removal"""
+    ifname = "test-ext-" + dev[0].ifname
+    try:
+        _test_wpas_ctrl_interface_add2(dev, apdev, ifname)
+    finally:
+        subprocess.call(['iw', 'dev', ifname, 'del'])
+
+def _test_wpas_ctrl_interface_add2(dev, apdev, ifname):
+    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+    subprocess.call(['iw', 'dev', dev[0].ifname, 'interface', 'add', ifname,
+                     'type', 'station'])
+    dev[0].interface_add(ifname, set_ifname=False, all_params=True)
+    wpas = WpaSupplicant(ifname=ifname)
+    wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(wpas, hapd)
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    del wpas
+    dev[0].global_request("INTERFACE_REMOVE " + ifname)
+    hwsim_utils.test_connectivity(dev[0], hapd)
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index 06f4c2b..f9b1213 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -8,15 +8,17 @@
 
 import logging
 logger = logging.getLogger()
+import subprocess
 
 import hwsim_utils
 from wpasupplicant import WpaSupplicant
+from utils import HwsimSkip
 
-def mesh_supported(dev):
-    flags = int(dev.get_driver_status_field('capa.flags'), 16)
-    if flags & 0x100000000:
-        return True
-    return False
+def check_mesh_support(dev, secure=False):
+    if "MESH" not in dev.get_capability("modes"):
+        raise HwsimSkip("Driver does not support mesh")
+    if secure and "SAE" not in dev.get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
 
 def check_mesh_scan(dev, params, other_started=False, beacon_int=0):
     if not other_started:
@@ -95,19 +97,17 @@
 
 def test_wpas_add_set_remove_support(dev):
     """wpa_supplicant MESH add/set/remove network support"""
+    check_mesh_support(dev[0])
     id = dev[0].add_network()
     dev[0].set_network(id, "mode", "5")
     dev[0].remove_network(id)
 
-def add_open_mesh_network(dev, ht_mode=False, freq="2412", start=True,
-                          beacon_int=0):
+def add_open_mesh_network(dev, freq="2412", start=True, beacon_int=0):
     id = dev.add_network()
     dev.set_network(id, "mode", "5")
     dev.set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev.set_network(id, "key_mgmt", "NONE")
     dev.set_network(id, "frequency", freq)
-    if ht_mode:
-        dev.set_network(id, "mesh_ht_mode", ht_mode)
     if beacon_int:
         dev.set_network(id, "beacon_int", str(beacon_int))
     if start:
@@ -116,8 +116,7 @@
 
 def test_wpas_mesh_group_added(dev):
     """wpa_supplicant MESH group add"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     add_open_mesh_network(dev[0])
 
     # Check for MESH-GROUP-STARTED event
@@ -126,9 +125,8 @@
 
 def test_wpas_mesh_group_remove(dev):
     """wpa_supplicant MESH group remove"""
-    if not mesh_supported(dev[0]):
-        return "skip"
-    add_open_mesh_network(dev[0], ht_mode="NOHT")
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
     # Check for MESH-GROUP-STARTED event
     check_mesh_group_added(dev[0])
     dev[0].mesh_group_remove()
@@ -138,10 +136,9 @@
 
 def test_wpas_mesh_peer_connected(dev):
     """wpa_supplicant MESH peer connected"""
-    if not mesh_supported(dev[0]):
-        return "skip"
-    add_open_mesh_network(dev[0], ht_mode="HT20", beacon_int=160)
-    add_open_mesh_network(dev[1], ht_mode="HT20", beacon_int=160)
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0], beacon_int=160)
+    add_open_mesh_network(dev[1], beacon_int=160)
 
     # Check for mesh joined
     check_mesh_group_added(dev[0])
@@ -154,8 +151,7 @@
 
 def test_wpas_mesh_peer_disconnected(dev):
     """wpa_supplicant MESH peer disconnected"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     add_open_mesh_network(dev[0])
     add_open_mesh_network(dev[1])
 
@@ -175,10 +171,9 @@
 
 def test_wpas_mesh_mode_scan(dev):
     """wpa_supplicant MESH scan support"""
-    if not mesh_supported(dev[0]):
-        return "skip"
-    add_open_mesh_network(dev[0], ht_mode="HT40+")
-    add_open_mesh_network(dev[1], ht_mode="HT40+", beacon_int=175)
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    add_open_mesh_network(dev[1], beacon_int=175)
 
     # Check for mesh joined
     check_mesh_group_added(dev[0])
@@ -189,10 +184,9 @@
 
 def test_wpas_mesh_open(dev, apdev):
     """wpa_supplicant open MESH network connectivity"""
-    if not mesh_supported(dev[0]):
-        return "skip"
-    add_open_mesh_network(dev[0], ht_mode="HT40-", freq="2462")
-    add_open_mesh_network(dev[1], ht_mode="HT40-", freq="2462")
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0], freq="2462")
+    add_open_mesh_network(dev[1], freq="2462")
 
     # Check for mesh joined
     check_mesh_group_added(dev[0])
@@ -207,8 +201,7 @@
 
 def test_wpas_mesh_open_no_auto(dev, apdev):
     """wpa_supplicant open MESH network connectivity"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     id = add_open_mesh_network(dev[0], start=False)
     dev[0].set_network(id, "dot11MeshMaxRetries", "16")
     dev[0].set_network(id, "dot11MeshRetryTimeout", "255")
@@ -241,8 +234,7 @@
 
 def test_wpas_mesh_secure(dev, apdev):
     """wpa_supplicant secure MESH network connectivity"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0], secure=True)
     dev[0].request("SET sae_groups ")
     id = add_mesh_secure_net(dev[0])
     dev[0].mesh_group_add(id)
@@ -264,8 +256,7 @@
 
 def test_wpas_mesh_secure_sae_group_mismatch(dev, apdev):
     """wpa_supplicant secure MESH and SAE group mismatch"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0], secure=True)
     addr0 = dev[0].p2p_interface_addr()
     addr1 = dev[1].p2p_interface_addr()
     addr2 = dev[2].p2p_interface_addr()
@@ -316,8 +307,7 @@
 
 def test_wpas_mesh_secure_sae_missing_password(dev, apdev):
     """wpa_supplicant secure MESH and missing SAE password"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0], secure=True)
     id = add_mesh_secure_net(dev[0], psk=False)
     dev[0].set_network(id, "psk", "8f20b381f9b84371d61b5080ad85cac3c61ab3ca9525be5b2d0f4da3d979187a")
     dev[0].mesh_group_add(id)
@@ -333,8 +323,7 @@
 
 def test_wpas_mesh_secure_no_auto(dev, apdev):
     """wpa_supplicant secure MESH network connectivity"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0], secure=True)
     dev[0].request("SET sae_groups 19")
     id = add_mesh_secure_net(dev[0])
     dev[0].mesh_group_add(id)
@@ -360,8 +349,7 @@
 
 def test_wpas_mesh_ctrl(dev):
     """wpa_supplicant ctrl_iface mesh command error cases"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     if "FAIL" not in dev[0].request("MESH_GROUP_ADD 123"):
         raise Exception("Unexpected MESH_GROUP_ADD success")
     id = dev[0].add_network()
@@ -377,8 +365,7 @@
 
 def test_wpas_mesh_dynamic_interface(dev):
     """wpa_supplicant mesh with dynamic interface"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     mesh0 = None
     mesh1 = None
     try:
@@ -455,18 +442,21 @@
 
 def test_wpas_mesh_max_peering(dev, apdev):
     """Mesh max peering limit"""
-    if not mesh_supported(dev[0]):
-        return "skip"
+    check_mesh_support(dev[0])
     try:
         dev[0].request("SET max_peer_links 1")
-        for i in range(3):
-            add_open_mesh_network(dev[i])
 
-        for i in range(3):
+        # first, connect dev[0] and dev[1]
+        add_open_mesh_network(dev[0])
+        add_open_mesh_network(dev[1])
+        for i in range(2):
             ev = dev[i].wait_event(["MESH-PEER-CONNECTED"])
             if ev is None:
                 raise Exception("dev%d did not connect with any peer" % i)
 
+        # add dev[2] which will try to connect with both dev[0] and dev[1],
+        # but can complete connection only with dev[1]
+        add_open_mesh_network(dev[2])
         for i in range(1, 3):
             ev = dev[i].wait_event(["MESH-PEER-CONNECTED"])
             if ev is None:
@@ -476,8 +466,136 @@
         if ev is not None:
             raise Exception("dev0 connection beyond max peering limit")
 
+        ev = dev[2].wait_event(["MESH-PEER-CONNECTED"], timeout=0.1)
+        if ev is not None:
+            raise Exception("dev2 reported unexpected peering: " + ev)
+
         for i in range(3):
             dev[i].mesh_group_remove()
             check_mesh_group_removed(dev[i])
     finally:
         dev[0].request("SET max_peer_links 99")
+
+def test_wpas_mesh_open_5ghz(dev, apdev):
+    """wpa_supplicant open MESH network on 5 GHz band"""
+    try:
+        _test_wpas_mesh_open_5ghz(dev, apdev)
+    finally:
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def _test_wpas_mesh_open_5ghz(dev, apdev):
+    check_mesh_support(dev[0])
+    subprocess.call(['iw', 'reg', 'set', 'US'])
+    for i in range(2):
+        for j in range(5):
+            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+            if ev is None:
+                raise Exception("No regdom change event")
+            if "alpha2=US" in ev:
+                break
+        add_open_mesh_network(dev[i], freq="5180")
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_wpas_mesh_password_mismatch(dev, apdev):
+    """Mesh network and one device with mismatching password"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    dev[2].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[2])
+    dev[2].set_network_quoted(id, "psk", "wrong password")
+    dev[2].mesh_group_add(id)
+
+    # The two peers with matching password need to be able to connect
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    ev = dev[2].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=20)
+    if ev is None:
+        raise Exception("dev2 did not report auth failure (1)")
+    ev = dev[2].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=20)
+    if ev is None:
+        raise Exception("dev2 did not report auth failure (2)")
+
+    count = 0
+    ev = dev[0].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=1)
+    if ev is None:
+        logger.info("dev0 did not report auth failure")
+    else:
+        if "addr=" + dev[2].own_addr() not in ev:
+            raise Exception("Unexpected peer address in dev0 event: " + ev)
+        count += 1
+
+    ev = dev[1].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=1)
+    if ev is None:
+        logger.info("dev1 did not report auth failure")
+    else:
+        if "addr=" + dev[2].own_addr() not in ev:
+            raise Exception("Unexpected peer address in dev1 event: " + ev)
+        count += 1
+
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+    for i in range(2):
+        try:
+            hwsim_utils.test_connectivity(dev[i], dev[2], timeout=1)
+            raise Exception("Data connectivity test passed unexpectedly")
+        except Exception, e:
+            if "data delivery failed" not in str(e):
+                raise
+
+    if count == 0:
+        raise Exception("Neither dev0 nor dev1 reported auth failure")
+
+def test_wpas_mesh_password_mismatch_retry(dev, apdev, params):
+    """Mesh password mismatch and retry [long]"""
+    if not params['long']:
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].set_network_quoted(id, "psk", "wrong password")
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    for i in range(4):
+        ev = dev[0].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=20)
+        if ev is None:
+            raise Exception("dev0 did not report auth failure (%d)" % i)
+        ev = dev[1].wait_event(["MESH-SAE-AUTH-FAILURE"], timeout=20)
+        if ev is None:
+            raise Exception("dev1 did not report auth failure (%d)" % i)
+
+    ev = dev[0].wait_event(["MESH-SAE-AUTH-BLOCKED"], timeout=10)
+    if ev is None:
+        raise Exception("dev0 did not report auth blocked")
+    ev = dev[1].wait_event(["MESH-SAE-AUTH-BLOCKED"], timeout=10)
+    if ev is None:
+        raise Exception("dev1 did not report auth blocked")
diff --git a/tests/hwsim/test_wpas_wmm_ac.py b/tests/hwsim/test_wpas_wmm_ac.py
index f68866e..d2d5596 100644
--- a/tests/hwsim/test_wpas_wmm_ac.py
+++ b/tests/hwsim/test_wpas_wmm_ac.py
@@ -20,12 +20,12 @@
     for ac in acm_list:
         params["wmm_ac_%s_acm" % (ac.lower())] = "1"
 
-    return hostapd.add_ap(apdev[0]['ifname'], params)
+    return hostapd.add_ap(apdev['ifname'], params)
 
 def test_tspec(dev, apdev):
     """Basic addts/delts tests"""
     # configure ap with VO and VI requiring admission-control
-    hapd = add_wmm_ap(apdev, ["VO", "VI"])
+    hapd = add_wmm_ap(apdev[0], ["VO", "VI"])
     dev[0].connect("wmm_ac", key_mgmt="NONE", scan_freq="2462")
     hwsim_utils.test_connectivity(dev[0], hapd)
     status = dev[0].request("WMM_AC_STATUS")
@@ -112,7 +112,7 @@
 def test_tspec_protocol(dev, apdev):
     """Protocol tests for addts/delts"""
     # configure ap with VO and VI requiring admission-control
-    hapd = add_wmm_ap(apdev, ["VO", "VI"])
+    hapd = add_wmm_ap(apdev[0], ["VO", "VI"])
     dev[0].connect("wmm_ac", key_mgmt="NONE", scan_freq="2462")
 
     dev[0].dump_monitor()
@@ -245,3 +245,36 @@
     msg['bssid'] = apdev[0]['bssid']
     msg['payload'] = struct.pack('BBBB', 17, 2, 0, 0)
     hapd.mgmt_tx(msg)
+
+def test_tspec_ap_roam_open(dev, apdev):
+    """Roam between two open APs while having tspecs"""
+    hapd0 = add_wmm_ap(apdev[0], ["VO", "VI"])
+    dev[0].connect("wmm_ac", key_mgmt="NONE")
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    dev[0].add_ts(5, 6)
+
+    hapd1 = add_wmm_ap(apdev[1], ["VO", "VI"])
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2462)
+    dev[0].roam(apdev[1]['bssid'])
+    hwsim_utils.test_connectivity(dev[0], hapd1)
+    if dev[0].tspecs():
+        raise Exception("TSPECs weren't deleted on roaming")
+
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2462)
+    dev[0].roam(apdev[0]['bssid'])
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+
+def test_tspec_reassoc(dev, apdev):
+    """Reassociation to same BSS while having tspecs"""
+    hapd0 = add_wmm_ap(apdev[0], ["VO", "VI"])
+    dev[0].connect("wmm_ac", key_mgmt="NONE")
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    dev[0].add_ts(5, 6)
+    last_tspecs = dev[0].tspecs()
+
+    dev[0].request("REASSOCIATE")
+    dev[0].wait_connected()
+
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    if dev[0].tspecs() != last_tspecs:
+        raise Exception("TSPECs weren't saved on reassociation")
diff --git a/tests/hwsim/tshark.py b/tests/hwsim/tshark.py
new file mode 100644
index 0000000..ee70cfd
--- /dev/null
+++ b/tests/hwsim/tshark.py
@@ -0,0 +1,54 @@
+#
+# tshark module - refactored from test_scan.py
+#
+# Copyright (c) 2014, Qualcomm Atheros, Inc.
+# Copyright (c) 2015, Intel Mobile Communications GmbH
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import subprocess
+import logging
+logger = logging.getLogger()
+
+
+_tshark_filter_arg = '-Y'
+
+def run_tshark(filename, filter, display=None, wait=True):
+    global _tshark_filter_arg
+
+    if wait:
+        # wait a bit to make it more likely for wlantest sniffer to have
+        # captured and written the results into a file that we can process here
+        time.sleep(1)
+
+    try:
+        arg = [ "tshark", "-r", filename,
+                _tshark_filter_arg, filter ]
+        if display:
+            arg.append('-Tfields')
+            for d in display:
+                arg.append('-e')
+                arg.append(d)
+        else:
+            arg.append('-V')
+        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                               stderr=open('/dev/null', 'w'))
+    except Exception, e:
+        logger.info("Could run run tshark check: " + str(e))
+        cmd = None
+        return None
+
+    out = cmd.communicate()[0]
+    res = cmd.wait()
+    if res == 1:
+        # remember this for efficiency
+        _tshark_filter_arg = '-R'
+        arg[3] = '-R'
+        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                               stderr=open('/dev/null', 'w'))
+        out = cmd.communicate()[0]
+        cmd.wait()
+
+    return out
diff --git a/tests/hwsim/utils.py b/tests/hwsim/utils.py
index 66589bb..43dd331 100644
--- a/tests/hwsim/utils.py
+++ b/tests/hwsim/utils.py
@@ -1,5 +1,5 @@
 # Testing utilities
-# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -13,3 +13,29 @@
             if len(val) == 2:
                 ifnames.append(val[0].strip(' '))
     return ifnames
+
+class HwsimSkip(Exception):
+    def __init__(self, reason):
+        self.reason = reason
+    def __str__(self):
+        return self.reason
+
+class alloc_fail(object):
+    def __init__(self, dev, count, funcs):
+        self._dev = dev
+        self._count = count
+        self._funcs = funcs
+    def __enter__(self):
+        cmd = "TEST_ALLOC_FAIL %d:%s" % (self._count, self._funcs)
+        if "OK" not in self._dev.request(cmd):
+            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
+    def __exit__(self, type, value, traceback):
+        if type is None:
+            if self._dev.request("GET_ALLOC_FAIL") != "0:%s" % self._funcs:
+                raise Exception("Allocation failure did not trigger")
+
+def require_under_vm():
+    with open('/proc/1/cmdline', 'r') as f:
+        cmd = f.read()
+        if "inside.sh" not in cmd:
+            raise HwsimSkip("Not running under VM")
diff --git a/tests/hwsim/vm/dbus.conf b/tests/hwsim/vm/dbus.conf
new file mode 100644
index 0000000..e64e44f
--- /dev/null
+++ b/tests/hwsim/vm/dbus.conf
@@ -0,0 +1,37 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <type>system</type>
+  <user>messagebus</user>
+  <fork/>
+  <standard_system_servicedirs/>
+  <servicehelper>/usr/lib/dbus-1.0/dbus-daemon-launch-helper</servicehelper>
+  <pidfile>/var/run/dbus/pid</pidfile>
+  <auth>EXTERNAL</auth>
+  <listen>unix:path=/var/run/dbus/system_bus_socket</listen>
+  <policy context="default">
+    <allow user="*"/>
+    <deny own="*"/>
+    <deny send_type="method_call"/>
+    <allow send_type="signal"/>
+    <allow send_requested_reply="true" send_type="method_return"/>
+    <allow send_requested_reply="true" send_type="error"/>
+    <allow receive_type="method_call"/>
+    <allow receive_type="method_return"/>
+    <allow receive_type="error"/>
+    <allow receive_type="signal"/>
+    <allow send_destination="org.freedesktop.DBus"/>
+    <deny send_destination="org.freedesktop.DBus"
+          send_interface="org.freedesktop.DBus"
+          send_member="UpdateActivationEnvironment"/>
+  </policy>
+  <policy user="root">
+    <allow own="fi.epitest.hostap.WPASupplicant"/>
+    <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
+    <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
+    <allow own="fi.w1.wpa_supplicant1"/>
+    <allow send_destination="fi.w1.wpa_supplicant1"/>
+    <allow send_interface="fi.w1.wpa_supplicant1"/>
+    <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
+  </policy>
+</busconfig>
diff --git a/tests/hwsim/vm/inside.sh b/tests/hwsim/vm/inside.sh
index b610d58..ffab4ee 100755
--- a/tests/hwsim/vm/inside.sh
+++ b/tests/hwsim/vm/inside.sh
@@ -45,10 +45,16 @@
 export PATH=/tmp/bin:$EPATH:$PATH
 
 # some tests assume adm/admin group(s) exist(s)
-echo 'adm:x:0:' > /etc/group
-echo 'admin:x:0:' >> /etc/group
+cat > /etc/group <<EOF
+adm:x:0:
+admin:x:0:
+messagebus:x:106:
+EOF
 # root should exist
-echo 'root:x:0:0:root:/tmp:/bin/bash' > /etc/passwd
+cat > /etc/passwd <<EOF
+root:x:0:0:root:/tmp:/bin/bash
+messagebus:x:102:106::/var/run/dbus:/bin/false
+EOF
 cat > /etc/ethertypes <<EOF
 IPv4	 	0800  	ip ip4
 ARP		0806	ether-arp
@@ -92,6 +98,11 @@
 	echo $TESTDIR/vm/uevent.sh > /sys/kernel/uevent_helper
 	COUNTRY=00 crda
 
+	mkdir -p /var/run/dbus
+	touch /var/run/dbus/hwsim-test
+	chown messagebus.messagebus /var/run/dbus
+	dbus-daemon --config-file=$TESTDIR/vm/dbus.conf --fork
+
 	cd $TESTDIR
 	./run-all.sh $ARGS </dev/ttyS0 >/dev/ttyS0 2>&1
 	if test -d /sys/kernel/debug/gcov ; then
diff --git a/tests/hwsim/vm/parallel-vm.py b/tests/hwsim/vm/parallel-vm.py
index 3b488be..5beb652 100755
--- a/tests/hwsim/vm/parallel-vm.py
+++ b/tests/hwsim/vm/parallel-vm.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python2
 #
 # Parallel VM test case executor
-# Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -16,6 +16,54 @@
 
 logger = logging.getLogger()
 
+# Test cases that take significantly longer time to execute than average.
+long_tests = [ "ap_roam_open",
+               "wpas_mesh_password_mismatch_retry",
+               "wpas_mesh_password_mismatch",
+               "hostapd_oom_wpa2_psk_connect",
+               "ap_hs20_fetch_osu_stop",
+               "ap_roam_wpa2_psk",
+               "ibss_wpa_none_ccmp",
+               "nfc_wps_er_handover_pk_hash_mismatch_sta",
+               "go_neg_peers_force_diff_freq",
+               "p2p_cli_invite",
+               "sta_ap_scan_2b",
+               "ap_pmf_sta_unprot_deauth_burst",
+               "ap_bss_add_remove_during_ht_scan",
+               "wext_scan_hidden",
+               "autoscan_exponential",
+               "nfc_p2p_client",
+               "wnm_bss_keep_alive",
+               "ap_inactivity_disconnect",
+               "scan_bss_expiration_age",
+               "autoscan_periodic",
+               "discovery_group_client",
+               "concurrent_p2pcli",
+               "ap_bss_add_remove",
+               "wpas_ap_wps",
+               "wext_pmksa_cache",
+               "ibss_wpa_none",
+               "ap_ht_40mhz_intolerant_ap",
+               "ibss_rsn",
+               "discovery_pd_retries",
+               "ap_wps_setup_locked_timeout",
+               "ap_vht160",
+               "dfs_radar",
+               "dfs",
+               "grpform_cred_ready_timeout",
+               "hostapd_oom_wpa2_eap_connect",
+               "wpas_ap_dfs",
+               "autogo_many",
+               "hostapd_oom_wpa2_eap",
+               "ibss_open",
+               "proxyarp_open_ebtables",
+               "radius_failover",
+               "obss_scan_40_intolerant",
+               "dbus_connect_oom",
+               "proxyarp_open",
+               "ap_wps_iteration",
+               "ap_wps_pbc_timeout" ]
+
 def get_failed(vm):
     failed = []
     for i in range(num_servers):
@@ -24,6 +72,7 @@
 
 def vm_read_stdout(vm, i):
     global total_started, total_passed, total_failed, total_skipped
+    global rerun_failures
 
     ready = False
     try:
@@ -48,7 +97,12 @@
         elif line.startswith("FAIL"):
             ready = True
             total_failed += 1
-            name = line.split(' ')[1]
+            vals = line.split(' ')
+            if len(vals) < 2:
+                logger.info("VM[%d] incomplete FAIL line: %s" % (i, line))
+                name = line
+            else:
+                name = vals[1]
             logger.debug("VM[%d] test case failed: %s" % (i, name))
             vm['failed'].append(name)
         elif line.startswith("NOT-FOUND"):
@@ -147,7 +201,8 @@
                 raise Exception("Unexpected test cases remaining from first round")
             completed_first_pass = True
             for name in get_failed(vm):
-                rerun_tests.append(name)
+                if rerun_failures:
+                    rerun_tests.append(name)
                 first_run_failures.append(name)
 
         for i in range(num_servers):
@@ -225,6 +280,8 @@
             scr.clrtoeol()
             if rerun_tests:
                 scr.addstr("(RETRY FAILED %d)" % len(rerun_tests))
+            elif rerun_failures:
+                pass
             elif first_run_failures:
                 scr.addstr("(RETRY FAILED)")
 
@@ -236,6 +293,8 @@
     time.sleep(0.3)
 
 def main():
+    import argparse
+    import os
     global num_servers
     global vm
     global dir
@@ -243,6 +302,7 @@
     global tests
     global first_run_failures
     global total_started, total_passed, total_failed, total_skipped
+    global rerun_failures
 
     total_started = 0
     total_passed = 0
@@ -250,27 +310,51 @@
     total_skipped = 0
 
     debug_level = logging.INFO
-
-    if len(sys.argv) < 2:
-        sys.exit("Usage: %s <number of VMs> [--debug] [--codecov] [params..]" % sys.argv[0])
-    num_servers = int(sys.argv[1])
-    if num_servers < 1:
-        sys.exit("Too small number of VMs")
-
+    rerun_failures = True
     timestamp = int(time.time())
 
-    idx = 2
+    scriptsdir = os.path.dirname(os.path.realpath(sys.argv[0]))
 
-    if len(sys.argv) > idx and sys.argv[idx] == "--debug":
-        idx += 1
+    p = argparse.ArgumentParser(description='run multiple testing VMs in parallel')
+    p.add_argument('num_servers', metavar='number of VMs', type=int, choices=range(1, 100),
+                   help="number of VMs to start")
+    p.add_argument('-f', dest='testmodules', metavar='<test module>',
+                   help='execute only tests from these test modules',
+                   type=str, nargs='+')
+    p.add_argument('-1', dest='no_retry', action='store_const', const=True, default=False,
+                   help="don't retry failed tests automatically")
+    p.add_argument('--debug', dest='debug', action='store_const', const=True, default=False,
+                   help="enable debug logging")
+    p.add_argument('--codecov', dest='codecov', action='store_const', const=True, default=False,
+                   help="enable code coverage collection")
+    p.add_argument('--shuffle-tests', dest='shuffle', action='store_const', const=True, default=False,
+                   help="shuffle test cases to randomize order")
+    p.add_argument('--short', dest='short', action='store_const', const=True,
+                   default=False,
+                   help="only run short-duration test cases")
+    p.add_argument('--long', dest='long', action='store_const', const=True,
+                   default=False,
+                   help="include long-duration test cases")
+    p.add_argument('--valgrind', dest='valgrind', action='store_const',
+                   const=True, default=False,
+                   help="run tests under valgrind")
+    p.add_argument('params', nargs='*')
+    args = p.parse_args()
+    num_servers = args.num_servers
+    rerun_failures = not args.no_retry
+    if args.debug:
         debug_level = logging.DEBUG
-
-    if len(sys.argv) > idx and sys.argv[idx] == "--codecov":
-        idx += 1
+    extra_args = []
+    if args.valgrind:
+        extra_args += [ '--valgrind' ]
+    if args.long:
+        extra_args += [ '--long' ]
+    if args.codecov:
         print "Code coverage - build separate binaries"
         logdir = "/tmp/hwsim-test-logs/" + str(timestamp)
         os.makedirs(logdir)
-        subprocess.check_call(['./build-codecov.sh', logdir])
+        subprocess.check_call([os.path.join(scriptsdir, 'build-codecov.sh'),
+                               logdir])
         codecov_args = ['--codecov_dir', logdir]
         codecov = True
     else:
@@ -278,18 +362,21 @@
         codecov = False
 
     first_run_failures = []
-    tests = []
-    cmd = [ '../run-tests.py', '-L' ] + sys.argv[idx:]
-    lst = subprocess.Popen(cmd, stdout=subprocess.PIPE)
-    for l in lst.stdout.readlines():
-        name = l.split(' ')[0]
-        tests.append(name)
+    if args.params:
+        tests = args.params
+    else:
+        tests = []
+        cmd = [ os.path.join(os.path.dirname(scriptsdir), 'run-tests.py'),
+                '-L' ]
+        if args.testmodules:
+            cmd += [ "-f" ]
+            cmd += args.testmodules
+        lst = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+        for l in lst.stdout.readlines():
+            name = l.split(' ')[0]
+            tests.append(name)
     if len(tests) == 0:
         sys.exit("No test cases selected")
-    if '-f' in sys.argv[idx:]:
-        extra_args = sys.argv[idx:]
-    else:
-        extra_args = [x for x in sys.argv[idx:] if x not in tests]
 
     dir = '/tmp/hwsim-test-logs'
     try:
@@ -297,47 +384,20 @@
     except:
         pass
 
-    if num_servers > 2 and len(tests) > 100:
+    if args.shuffle:
+        from random import shuffle
+        shuffle(tests)
+    elif num_servers > 2 and len(tests) > 100:
         # Move test cases with long duration to the beginning as an
         # optimization to avoid last part of the test execution running a long
         # duration test case on a single VM while all other VMs have already
         # completed their work.
-        long = [ "ap_roam_open",
-                 "ap_hs20_fetch_osu_stop",
-                 "ap_roam_wpa2_psk",
-                 "ibss_wpa_none_ccmp",
-                 "nfc_wps_er_handover_pk_hash_mismatch_sta",
-                 "go_neg_peers_force_diff_freq",
-                 "p2p_cli_invite",
-                 "sta_ap_scan_2b",
-                 "ap_pmf_sta_unprot_deauth_burst",
-                 "ap_bss_add_remove_during_ht_scan",
-                 "wext_scan_hidden",
-                 "autoscan_exponential",
-                 "nfc_p2p_client",
-                 "wnm_bss_keep_alive",
-                 "ap_inactivity_disconnect",
-                 "scan_bss_expiration_age",
-                 "autoscan_periodic",
-                 "discovery_group_client",
-                 "concurrent_p2pcli",
-                 "ap_bss_add_remove",
-                 "wpas_ap_wps",
-                 "wext_pmksa_cache",
-                 "ibss_wpa_none",
-                 "ap_ht_40mhz_intolerant_ap",
-                 "ibss_rsn",
-                 "discovery_pd_retries",
-                 "ap_wps_setup_locked_timeout",
-                 "ap_vht160",
-                 "dfs_radar",
-                 "dfs",
-                 "grpform_cred_ready_timeout",
-                 "ap_wps_pbc_timeout" ]
-        for l in long:
+        for l in long_tests:
             if l in tests:
                 tests.remove(l)
                 tests.insert(0, l)
+    if args.short:
+        tests = [t for t in tests if t not in long_tests]
 
     logger.setLevel(debug_level)
     log_handler = logging.FileHandler('parallel-vm.log')
@@ -351,7 +411,8 @@
     for i in range(0, num_servers):
         print("\rStarting virtual machine {}/{}".format(i + 1, num_servers)),
         logger.info("Starting virtual machine {}/{}".format(i + 1, num_servers))
-        cmd = ['./vm-run.sh', '--delay', str(i), '--timestamp', str(timestamp),
+        cmd = [os.path.join(scriptsdir, 'vm-run.sh'), '--delay', str(i),
+               '--timestamp', str(timestamp),
                '--ext', 'srv.%d' % (i + 1),
                '-i'] + codecov_args + extra_args
         vm[i] = {}
@@ -389,7 +450,9 @@
         double_failed.append(name)
     for test in first_run_failures:
         double_failed.remove(test)
-    if failed and not double_failed:
+    if not rerun_failures:
+        pass
+    elif failed and not double_failed:
         print "All failed cases passed on retry"
         logger.info("All failed cases passed on retry")
     elif double_failed:
@@ -420,14 +483,16 @@
     if codecov:
         print "Code coverage - preparing report"
         for i in range(num_servers):
-            subprocess.check_call(['./process-codecov.sh',
+            subprocess.check_call([os.path.join(scriptsdir,
+                                                'process-codecov.sh'),
                                    logdir + ".srv.%d" % (i + 1),
                                    str(i)])
-        subprocess.check_call(['./combine-codecov.sh', logdir])
+        subprocess.check_call([os.path.join(scriptsdir, 'combine-codecov.sh'),
+                               logdir])
         print "file://%s/index.html" % logdir
         logger.info("Code coverage report: file://%s/index.html" % logdir)
 
-    if double_failed:
+    if double_failed or (failed and not rerun_failures):
         logger.info("Test run complete - failures found")
         sys.exit(2)
     if failed:
diff --git a/tests/hwsim/vm/vm-run.sh b/tests/hwsim/vm/vm-run.sh
index 77703bf..a748e10 100755
--- a/tests/hwsim/vm/vm-run.sh
+++ b/tests/hwsim/vm/vm-run.sh
@@ -9,7 +9,7 @@
 LOGS=/tmp/hwsim-test-logs
 
 # increase the memory size if you want to run with valgrind, 512 MB works
-MEMORY=128
+MEMORY=192
 
 # Some ubuntu systems (notably 12.04) have issues with this - since the guest
 # mounts as read-only it should be safe to not specify ,readonly. Override in
diff --git a/tests/hwsim/wlantest.py b/tests/hwsim/wlantest.py
index 85ecb88..5f6b4ac 100644
--- a/tests/hwsim/wlantest.py
+++ b/tests/hwsim/wlantest.py
@@ -128,6 +128,11 @@
         if "MFPC" not in res:
             raise Exception("STA did not enable PMF")
 
+    def require_sta_no_pmf(self, bssid, addr):
+        res = self.info_sta("rsn_capab", bssid, addr)
+        if "MFPC" in res:
+            raise Exception("STA enabled PMF")
+
     def require_sta_key_mgmt(self, bssid, addr, key_mgmt):
         res = self.info_sta("key_mgmt", bssid, addr)
         if key_mgmt not in res:
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index 3f5bd6f..e29b3fc 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -33,6 +33,13 @@
         else:
             self.global_mon = None
 
+    def close_ctrl(self):
+        if self.global_mon:
+            self.global_mon.detach()
+            self.global_mon = None
+            self.global_ctrl = None
+        self.remove_ifname()
+
     def set_ifname(self, ifname):
         self.ifname = ifname
         self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
@@ -46,7 +53,9 @@
             self.ctrl = None
             self.ifname = None
 
-    def interface_add(self, ifname, config="", driver="nl80211", drv_params=None):
+    def interface_add(self, ifname, config="", driver="nl80211",
+                      drv_params=None, br_ifname=None, create=False,
+                      set_ifname=True, all_params=False):
         try:
             groups = subprocess.check_output(["id"])
             group = "admin" if "(admin)" in groups else "adm"
@@ -55,17 +64,34 @@
         cmd = "INTERFACE_ADD " + ifname + "\t" + config + "\t" + driver + "\tDIR=/var/run/wpa_supplicant GROUP=" + group
         if drv_params:
             cmd = cmd + '\t' + drv_params
+        if br_ifname:
+            if not drv_params:
+                cmd += '\t'
+            cmd += '\t' + br_ifname
+        if create:
+            if not br_ifname:
+                cmd += '\t'
+                if not drv_params:
+                    cmd += '\t'
+            cmd += '\tcreate'
+        if all_params and not create:
+            if not br_ifname:
+                cmd += '\t'
+                if not drv_params:
+                    cmd += '\t'
+            cmd += '\t'
         if "FAIL" in self.global_request(cmd):
             raise Exception("Failed to add a dynamic wpa_supplicant interface")
-        self.set_ifname(ifname)
+        if not create and set_ifname:
+            self.set_ifname(ifname)
 
     def interface_remove(self, ifname):
         self.remove_ifname()
         self.global_request("INTERFACE_REMOVE " + ifname)
 
-    def request(self, cmd):
+    def request(self, cmd, timeout=10):
         logger.debug(self.ifname + ": CTRL: " + cmd)
-        return self.ctrl.request(cmd)
+        return self.ctrl.request(cmd, timeout=timeout)
 
     def global_request(self, cmd):
         if self.global_iface is None:
@@ -121,13 +147,13 @@
             logger.error(self.ifname + ": Driver scan state did not clear")
             print "Trying to clear cfg80211/mac80211 scan state"
             try:
-                cmd = ["sudo", "ifconfig", self.ifname, "down"]
+                cmd = ["ifconfig", self.ifname, "down"]
                 subprocess.call(cmd)
             except subprocess.CalledProcessError, e:
                 logger.info("ifconfig failed: " + str(e.returncode))
                 logger.info(e.output)
             try:
-                cmd = ["sudo", "ifconfig", self.ifname, "up"]
+                cmd = ["ifconfig", self.ifname, "up"]
                 subprocess.call(cmd)
             except subprocess.CalledProcessError, e:
                 logger.info("ifconfig failed: " + str(e.returncode))
@@ -195,6 +221,12 @@
         else:
             self.request("SET auto_interworking 0")
 
+    def interworking_add_network(self, bssid):
+        id = self.request("INTERWORKING_ADD_NETWORK " + bssid)
+        if "FAIL" in id or "OK" in id:
+            raise Exception("INTERWORKING_ADD_NETWORK failed")
+        return int(id)
+
     def add_cred(self):
         id = self.request("ADD_CRED")
         if "FAIL" in id:
@@ -246,7 +278,7 @@
 
     def select_network(self, id, freq=None):
         if freq:
-            extra = " freq=" + freq
+            extra = " freq=" + str(freq)
         else:
             extra = ""
         id = self.request("SELECT_NETWORK " + str(id) + extra)
@@ -369,7 +401,7 @@
         return self.global_request("P2P_LISTEN")
 
     def p2p_find(self, social=False, progressive=False, dev_id=None,
-                 dev_type=None, delay=None):
+                 dev_type=None, delay=None, freq=None):
         cmd = "P2P_FIND"
         if social:
             cmd = cmd + " type=social"
@@ -381,6 +413,8 @@
             cmd = cmd + " dev_type=" + dev_type
         if delay:
             cmd = cmd + " delay=" + str(delay)
+        if freq:
+            cmd = cmd + " freq=" + str(freq)
         return self.global_request(cmd)
 
     def p2p_stop_find(self):
@@ -494,7 +528,10 @@
         if not self.discover_peer(peer):
             raise Exception("Peer " + peer + " not found")
         self.dump_monitor()
-        cmd = "P2P_CONNECT " + peer + " " + pin + " " + method + " auth"
+        if pin:
+            cmd = "P2P_CONNECT " + peer + " " + pin + " " + method + " auth"
+        else:
+            cmd = "P2P_CONNECT " + peer + " " + method + " auth"
         if go_intent:
             cmd = cmd + ' go_intent=' + str(go_intent)
         if freq:
@@ -631,7 +668,7 @@
             except:
                 pass
             self.gctrl_mon = None
-        ev = self.wait_event(["P2P-GROUP-REMOVED"], timeout=3)
+        ev = self.wait_global_event(["P2P-GROUP-REMOVED"], timeout=3)
         if ev is None:
             raise Exception("Group removal event timed out")
         if "reason=GO_ENDING_SESSION" not in ev:
@@ -723,6 +760,15 @@
             raise Exception("Failed to request TDLS teardown")
         return None
 
+    def tspecs(self):
+        """Return (tsid, up) tuples representing current tspecs"""
+        res = self.request("WMM_AC_STATUS")
+        tspecs = re.findall(r"TSID=(\d+) UP=(\d+)", res)
+        tspecs = [tuple(map(int, tspec)) for tspec in tspecs]
+
+        logger.debug("tspecs: " + str(tspecs))
+        return tspecs
+
     def add_ts(self, tsid, up, direction="downlink", expect_failure=False,
                extra=None):
         params = {
@@ -754,6 +800,9 @@
         if "tsid=%d" % (tsid) not in ev:
             raise Exception("ADDTS failed (invalid tsid in TSPEC-ADDED)")
 
+        if not (tsid, up) in self.tspecs():
+            raise Exception("ADDTS failed (tsid not in tspec list)")
+
     def del_ts(self, tsid):
         if self.request("WMM_AC_DELTS %d" % (tsid)).strip() != "OK":
             raise Exception("DELTS failed")
@@ -764,6 +813,10 @@
         if "tsid=%d" % (tsid) not in ev:
             raise Exception("DELTS failed (invalid tsid in TSPEC-REMOVED)")
 
+        tspecs = [(t, u) for (t, u) in self.tspecs() if t == tsid]
+        if tspecs:
+            raise Exception("DELTS failed (still in tspec list)")
+
     def connect(self, ssid=None, ssid2=None, **kwargs):
         logger.info("Connect STA " + self.ifname + " to AP")
         id = self.add_network()
@@ -777,7 +830,8 @@
                    "private_key_passwd", "ca_cert2", "client_cert2",
                    "private_key2", "phase1", "phase2", "domain_suffix_match",
                    "altsubject_match", "subject_match", "pac_file", "dh_file",
-                   "bgscan", "ht_mcs", "id_str", "openssl_ciphers" ]
+                   "bgscan", "ht_mcs", "id_str", "openssl_ciphers",
+                   "domain_match" ]
         for field in quoted:
             if field in kwargs and kwargs[field]:
                 self.set_network_quoted(id, field, kwargs[field])
@@ -790,7 +844,8 @@
                        "disable_max_amsdu", "ampdu_factor", "ampdu_density",
                        "disable_ht40", "disable_sgi", "disable_ldpc",
                        "ht40_intolerant", "update_identifier", "mac_addr",
-                       "erp", "bg_scan_period" ]
+                       "erp", "bg_scan_period", "bssid_blacklist",
+                       "bssid_whitelist", "mem_only_psk", "eap_workaround" ]
         for field in not_quoted:
             if field in kwargs and kwargs[field]:
                 self.set_network(id, field, kwargs[field])
@@ -836,11 +891,11 @@
         if ev is None:
             raise Exception("Scan timed out")
 
-    def scan_for_bss(self, bssid, freq=None, force_scan=False):
+    def scan_for_bss(self, bssid, freq=None, force_scan=False, only_new=False):
         if not force_scan and self.get_bss(bssid) is not None:
             return
         for i in range(0, 10):
-            self.scan(freq=freq, type="ONLY")
+            self.scan(freq=freq, type="ONLY", only_new=only_new)
             if self.get_bss(bssid) is not None:
                 return
         raise Exception("Could not find BSS " + bssid + " in scan")
@@ -913,8 +968,14 @@
             return None
         return res.split(' ')
 
-    def get_bss(self, bssid):
-        res = self.request("BSS " + bssid)
+    def get_bss(self, bssid, ifname=None):
+	if not ifname or ifname == self.ifname:
+            res = self.request("BSS " + bssid)
+        elif ifname == self.group_ifname:
+            res = self.group_request("BSS " + bssid)
+        else:
+            return None
+
         if "FAIL" in res:
             return None
         lines = res.splitlines()
@@ -1002,3 +1063,17 @@
         if ev is None:
             raise Exception(error)
         return ev
+
+    def get_group_ifname(self):
+        return self.group_ifname if self.group_ifname else self.ifname
+
+    def get_config(self):
+        res = self.request("DUMP")
+        if res.startswith("FAIL"):
+            raise Exception("DUMP failed")
+        lines = res.splitlines()
+        vals = dict()
+        for l in lines:
+            [name,value] = l.split('=', 1)
+            vals[name] = value
+        return vals
diff --git a/tests/p2p-fuzzer/Makefile b/tests/p2p-fuzzer/Makefile
new file mode 100644
index 0000000..4f81ef1
--- /dev/null
+++ b/tests/p2p-fuzzer/Makefile
@@ -0,0 +1,51 @@
+all: p2p-fuzzer
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+SRC=../../src
+
+CFLAGS += -I$(SRC)
+
+$(SRC)/utils/libutils.a:
+	$(MAKE) -C $(SRC)/utils
+
+$(SRC)/common/libcommon.a:
+	$(MAKE) -C $(SRC)/common
+
+$(SRC)/crypto/libcrypto.a:
+	$(MAKE) -C $(SRC)/crypto
+
+$(SRC)/tls/libtls.a:
+	$(MAKE) -C $(SRC)/tls
+
+$(SRC)/p2p/libp2p.a:
+	$(MAKE) -C $(SRC)/p2p
+
+$(SRC)/wps/libwps.a:
+	$(MAKE) -C $(SRC)/wps
+
+LIBS += $(SRC)/utils/libutils.a
+LIBS += $(SRC)/common/libcommon.a
+LIBS += $(SRC)/crypto/libcrypto.a
+LIBS += $(SRC)/p2p/libp2p.a
+LIBS += $(SRC)/tls/libtls.a
+LIBS += $(SRC)/wps/libwps.a
+
+p2p-fuzzer: p2p-fuzzer.o $(LIBS)
+	$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+	$(MAKE) -C $(SRC) clean
+	rm -f p2p-fuzzer *~ *.o *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/tests/p2p-fuzzer/go-neg-req.dat b/tests/p2p-fuzzer/go-neg-req.dat
new file mode 100644
index 0000000..ed06834
--- /dev/null
+++ b/tests/p2p-fuzzer/go-neg-req.dat
Binary files differ
diff --git a/tests/p2p-fuzzer/invitation-req.dat b/tests/p2p-fuzzer/invitation-req.dat
new file mode 100644
index 0000000..5991f3e
--- /dev/null
+++ b/tests/p2p-fuzzer/invitation-req.dat
Binary files differ
diff --git a/tests/p2p-fuzzer/p2p-fuzzer.c b/tests/p2p-fuzzer/p2p-fuzzer.c
new file mode 100644
index 0000000..dcc1d72
--- /dev/null
+++ b/tests/p2p-fuzzer/p2p-fuzzer.c
@@ -0,0 +1,213 @@
+/*
+ * wpa_supplicant - P2P fuzzer
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
+
+
+static void debug_print(void *ctx, int level, const char *msg)
+{
+	wpa_printf(level, "P2P: %s", msg);
+}
+
+
+static void find_stopped(void *ctx)
+{
+}
+
+
+static int start_listen(void *ctx, unsigned int freq,
+			unsigned int duration,
+			const struct wpabuf *probe_resp_ie)
+{
+	return 0;
+}
+
+
+static void stop_listen(void *ctx)
+{
+}
+
+
+static void dev_found(void *ctx, const u8 *addr,
+		      const struct p2p_peer_info *info,
+		      int new_device)
+{
+}
+
+
+static void dev_lost(void *ctx, const u8 *dev_addr)
+{
+}
+
+
+static int send_action(void *ctx, unsigned int freq, const u8 *dst,
+		       const u8 *src, const u8 *bssid, const u8 *buf,
+		       size_t len, unsigned int wait_time)
+{
+	return 0;
+}
+
+
+static void send_action_done(void *ctx)
+{
+}
+
+
+static void go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+{
+}
+
+
+static struct p2p_data * init_p2p(void)
+{
+	struct p2p_config p2p;
+
+	os_memset(&p2p, 0, sizeof(p2p));
+	p2p.max_peers = 100;
+	p2p.passphrase_len = 8;
+	p2p.channels.reg_classes = 1;
+	p2p.channels.reg_class[0].reg_class = 81;
+	p2p.channels.reg_class[0].channel[0] = 1;
+	p2p.channels.reg_class[0].channel[1] = 2;
+	p2p.channels.reg_class[0].channels = 2;
+	p2p.debug_print = debug_print;
+	p2p.find_stopped = find_stopped;
+	p2p.start_listen = start_listen;
+	p2p.stop_listen = stop_listen;
+	p2p.dev_found = dev_found;
+	p2p.dev_lost = dev_lost;
+	p2p.send_action = send_action;
+	p2p.send_action_done = send_action_done;
+	p2p.go_neg_req_rx = go_neg_req_rx;
+
+	return p2p_init(&p2p);
+}
+
+
+struct arg_ctx {
+	struct p2p_data *p2p;
+	const char *fname;
+};
+
+
+static void test_send_proberesp(void *eloop_data, void *user_ctx)
+{
+	struct arg_ctx *ctx = eloop_data;
+	char *data;
+	size_t len;
+	struct os_reltime rx_time;
+
+	wpa_printf(MSG_INFO, "p2p-fuzzer: Send proberesp '%s'", ctx->fname);
+
+	data = os_readfile(ctx->fname, &len);
+	if (!data) {
+		wpa_printf(MSG_ERROR, "Could not read '%s'", ctx->fname);
+		return;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "fuzzer - IEs", data, len);
+
+	os_memset(&rx_time, 0, sizeof(rx_time));
+	p2p_scan_res_handler(ctx->p2p, (u8 *) "\x02\x00\x00\x00\x01\x00", 2412,
+			     &rx_time, 0, (u8 *) data, len);
+	p2p_scan_res_handled(ctx->p2p);
+
+	os_free(data);
+	eloop_terminate();
+}
+
+
+static void test_send_action(void *eloop_data, void *user_ctx)
+{
+	struct arg_ctx *ctx = eloop_data;
+	char *data;
+	size_t len;
+	struct os_reltime rx_time;
+	struct ieee80211_mgmt *mgmt;
+
+	wpa_printf(MSG_INFO, "p2p-fuzzer: Send action '%s'", ctx->fname);
+
+	data = os_readfile(ctx->fname, &len);
+	if (!data) {
+		wpa_printf(MSG_ERROR, "Could not read '%s'", ctx->fname);
+		return;
+	}
+	if (len < IEEE80211_HDRLEN + 1)
+		goto out;
+
+	wpa_hexdump(MSG_MSGDUMP, "fuzzer - action", data, len);
+
+	mgmt = (struct ieee80211_mgmt *) data;
+	os_memset(&rx_time, 0, sizeof(rx_time));
+	p2p_rx_action(ctx->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
+		      mgmt->u.action.category,
+		      (u8 *) data + IEEE80211_HDRLEN + 1,
+		      len - IEEE80211_HDRLEN - 1, 2412);
+
+out:
+	os_free(data);
+	eloop_terminate();
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct p2p_data *p2p;
+	struct arg_ctx ctx;
+
+	/* TODO: probreq and wpas_p2p_probe_req_rx() */
+
+	if (argc < 3) {
+		printf("usage: %s <proberesp|action> <file>\n", argv[0]);
+		return -1;
+	}
+
+	if (os_program_init())
+		return -1;
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	p2p = init_p2p();
+	if (!p2p) {
+		wpa_printf(MSG_ERROR, "P2P init failed");
+		return -1;
+	}
+
+	ctx.p2p = p2p;
+	ctx.fname = argv[2];
+
+	if (os_strcmp(argv[1], "proberesp") == 0) {
+		eloop_register_timeout(0, 0, test_send_proberesp, &ctx, NULL);
+	} else if (os_strcmp(argv[1], "action") == 0) {
+		eloop_register_timeout(0, 0, test_send_action, &ctx, NULL);
+	} else {
+		wpa_printf(MSG_ERROR, "Unsupported test type '%s'", argv[1]);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Starting eloop");
+	eloop_run();
+	wpa_printf(MSG_DEBUG, "eloop done");
+
+	p2p_deinit(p2p);
+	eloop_destroy();
+	os_program_deinit();
+
+	return 0;
+}
diff --git a/tests/p2p-fuzzer/p2ps-pd-req.dat b/tests/p2p-fuzzer/p2ps-pd-req.dat
new file mode 100644
index 0000000..7e1b6d9
--- /dev/null
+++ b/tests/p2p-fuzzer/p2ps-pd-req.dat
Binary files differ
diff --git a/tests/p2p-fuzzer/proberesp-go.dat b/tests/p2p-fuzzer/proberesp-go.dat
new file mode 100644
index 0000000..8541652
--- /dev/null
+++ b/tests/p2p-fuzzer/proberesp-go.dat
Binary files differ
diff --git a/tests/p2p-fuzzer/proberesp.dat b/tests/p2p-fuzzer/proberesp.dat
new file mode 100644
index 0000000..8d997d1
--- /dev/null
+++ b/tests/p2p-fuzzer/proberesp.dat
Binary files differ
diff --git a/tests/test-aes.c b/tests/test-aes.c
index e8c0908..9d76c07 100644
--- a/tests/test-aes.c
+++ b/tests/test-aes.c
@@ -11,7 +11,6 @@
 #include "common.h"
 #include "crypto/crypto.h"
 #include "crypto/aes_wrap.h"
-#include "crypto/aes_siv.h"
 
 #define BLOCK_SIZE 16
 
@@ -52,115 +51,6 @@
 }
 
 
-static int test_eax(void)
-{
-	u8 msg[] = { 0xF7, 0xFB };
-	u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
-		     0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
-	u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
-		       0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
-	u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
-	u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
-			0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
-			0x67, 0xE5 };
-	u8 data[sizeof(msg)], tag[BLOCK_SIZE];
-
-	memcpy(data, msg, sizeof(msg));
-	if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
-				data, sizeof(data), tag)) {
-		printf("AES-128 EAX mode encryption failed\n");
-		return 1;
-	}
-	if (memcmp(data, cipher, sizeof(data)) != 0) {
-		printf("AES-128 EAX mode encryption returned invalid cipher "
-		       "text\n");
-		return 1;
-	}
-	if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
-		printf("AES-128 EAX mode encryption returned invalid tag\n");
-		return 1;
-	}
-
-	if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
-				data, sizeof(data), tag)) {
-		printf("AES-128 EAX mode decryption failed\n");
-		return 1;
-	}
-	if (memcmp(data, msg, sizeof(data)) != 0) {
-		printf("AES-128 EAX mode decryption returned invalid plain "
-		       "text\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static int test_cbc(void)
-{
-	struct cbc_test_vector {
-		u8 key[16];
-		u8 iv[16];
-		u8 plain[32];
-		u8 cipher[32];
-		size_t len;
-	} vectors[] = {
-		{
-			{ 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
-			  0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
-			{ 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
-			  0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
-			"Single block msg",
-			{ 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
-			  0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
-			16
-		},
-		{
-			{ 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
-			  0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
-			{ 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
-			  0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
-			{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-			  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-			  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-			  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
-			{ 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
-			  0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
-			  0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
-			  0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
-			32
-		}
-	};
-	int ret = 0;
-	u8 *buf;
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(vectors); i++) {
-		struct cbc_test_vector *tv = &vectors[i];
-		buf = malloc(tv->len);
-		if (buf == NULL) {
-			ret++;
-			break;
-		}
-		memcpy(buf, tv->plain, tv->len);
-		if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
-		    memcmp(buf, tv->cipher, tv->len) != 0) {
-			printf("AES-CBC encrypt %d failed\n", i);
-			ret++;
-		}
-		memcpy(buf, tv->cipher, tv->len);
-		if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
-		    memcmp(buf, tv->plain, tv->len) != 0) {
-			printf("AES-CBC decrypt %d failed\n", i);
-			ret++;
-		}
-		free(buf);
-	}
-
-	return ret;
-}
-
-
 /*
  * GCM test vectors from
  * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
@@ -439,375 +329,6 @@
 }
 
 
-static int test_siv(void)
-{
-	u8 key[] = {
-		0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
-		0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
-		0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-		0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-	};
-	u8 ad[] = {
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-		0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
-	};
-	u8 plaintext[] = {
-		0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
-		0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
-	};
-	u8 iv_c[] = {
-		0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
-		0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
-		0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
-		0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
-	};
-	u8 out[2 * BLOCK_SIZE + sizeof(plaintext)];
-	const u8 *addr[1];
-	size_t len[1];
-
-	addr[0] = ad;
-	len[0] = sizeof(ad);
-
-	if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
-			    1, addr, len, out)) {
-		printf("AES-SIV mode encryption failed\n");
-		return 1;
-	}
-	if (memcmp(out, iv_c, sizeof(iv_c)) != 0) {
-		printf("AES-SIV mode encryption returned invalid cipher "
-		       "text\n");
-		return 1;
-	}
-
-	if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
-		printf("AES-SIV mode decryption failed\n");
-		return 1;
-	}
-	if (memcmp(out, plaintext, sizeof(plaintext)) != 0) {
-		printf("AES-SIV mode decryption returned invalid plain text\n");
-		return 1;
-	}
-	printf("AES-SIV test passed\n");
-
-	return 0;
-}
-
-
-/* OMAC1 AES-128 test vectors from
- * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
- * which are same as the examples from NIST SP800-38B
- * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
- */
-
-struct omac1_test_vector {
-	u8 k[16];
-	u8 msg[64];
-	int msg_len;
-	u8 tag[16];
-};
-
-static struct omac1_test_vector test_vectors[] =
-{
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ },
-		0,
-		{ 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
-		  0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
-		16,
-		{ 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
-		  0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
-		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
-		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
-		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
-		40,
-		{ 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
-		  0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
-		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
-		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
-		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
-		  0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
-		  0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
-		  0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
-		64,
-		{ 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
-		  0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
-	},
-};
-
-
-static int test_key_wrap(void)
-{
-	unsigned int i;
-	int ret = 0;
-
-	/* RFC 3394 - Test vector 4.1 */
-	u8 kek41[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
-	};
-	u8 plain41[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-	};
-	u8 crypt41[] = {
-		0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
-		0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
-		0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
-	};
-	/* RFC 3394 - Test vector 4.2 */
-	u8 kek42[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
-	};
-	u8 plain42[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-	};
-	u8 crypt42[] = {
-		0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
-		0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
-		0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
-	};
-	/* RFC 3394 - Test vector 4.3 */
-	u8 kek43[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
-	};
-	u8 plain43[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-	};
-	u8 crypt43[] = {
-		0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
-		0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
-		0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
-	};
-	/* RFC 3394 - Test vector 4.4 */
-	u8 kek44[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
-	};
-	u8 plain44[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
-	};
-	u8 crypt44[] = {
-		0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
-		0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
-		0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
-		0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
-	};
-	/* RFC 3394 - Test vector 4.5 */
-	u8 kek45[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
-	};
-	u8 plain45[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
-	};
-	u8 crypt45[] = {
-		0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
-		0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
-		0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
-		0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,
-	};
-	/* RFC 3394 - Test vector 4.6 */
-	u8 kek46[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
-	};
-	u8 plain46[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-	};
-	u8 crypt46[] = {
-		0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
-		0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
-		0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
-		0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
-		0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21
-	};
-	u8 result[40];
-
-	printf("RFC 3394 - Test vector 4.1\n");
-	if (aes_wrap(kek41, sizeof(kek41), sizeof(plain41) / 8, plain41,
-		     result)) {
-		printf("AES-WRAP-128 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt41, sizeof(crypt41)) != 0) {
-		printf("AES-WRAP-128 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek41, sizeof(kek41), sizeof(plain41) / 8, crypt41,
-		       result)) {
-		printf("AES-UNWRAP-128 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain41, sizeof(plain41)) != 0) {
-		printf("AES-UNWRAP-128 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain41); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	printf("RFC 3394 - Test vector 4.2\n");
-	if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
-		     result)) {
-		printf("AES-WRAP-192 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt42, sizeof(crypt42)) != 0) {
-		printf("AES-WRAP-192 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek42, sizeof(kek42), sizeof(plain42) / 8, crypt42,
-		       result)) {
-		printf("AES-UNWRAP-192 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain42, sizeof(plain42)) != 0) {
-		printf("AES-UNWRAP-192 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain42); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	printf("RFC 3394 - Test vector 4.3\n");
-	if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
-		     result)) {
-		printf("AES-WRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt43, sizeof(crypt43)) != 0) {
-		printf("AES-WRAP-256 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek43, sizeof(kek43), sizeof(plain43) / 8, crypt43,
-		       result)) {
-		printf("AES-UNWRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain43, sizeof(plain43)) != 0) {
-		printf("AES-UNWRAP-256 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain43); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	printf("RFC 3394 - Test vector 4.4\n");
-	if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
-		     result)) {
-		printf("AES-WRAP-192 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt44, sizeof(crypt44)) != 0) {
-		printf("AES-WRAP-192 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek44, sizeof(kek44), sizeof(plain44) / 8, crypt44,
-		       result)) {
-		printf("AES-UNWRAP-192 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain44, sizeof(plain44)) != 0) {
-		printf("AES-UNWRAP-192 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain44); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	printf("RFC 3394 - Test vector 4.5\n");
-	if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
-		     result)) {
-		printf("AES-WRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt45, sizeof(crypt45)) != 0) {
-		printf("AES-WRAP-256 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(crypt45); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-	if (aes_unwrap(kek45, sizeof(kek45), sizeof(plain45) / 8, crypt45,
-		       result)) {
-		printf("AES-UNWRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain45, sizeof(plain45)) != 0) {
-		printf("AES-UNWRAP-256 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain45); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	printf("RFC 3394 - Test vector 4.6\n");
-	if (aes_wrap(kek46, sizeof(kek46), sizeof(plain46) / 8, plain46,
-		     result)) {
-		printf("AES-WRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt46, sizeof(crypt46)) != 0) {
-		printf("AES-WRAP-256 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek46, sizeof(kek46), sizeof(plain46) / 8, crypt46,
-		       result)) {
-		printf("AES-UNWRAP-256 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain46, sizeof(plain46)) != 0) {
-		printf("AES-UNWRAP-256 failed\n");
-		ret++;
-		for (i = 0; i < sizeof(plain46); i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-	return ret;
-}
-
-
 static int test_nist_key_wrap_ae(const char *fname)
 {
 	FILE *f;
@@ -1085,55 +606,17 @@
 
 int main(int argc, char *argv[])
 {
-	u8 result[24];
 	int ret = 0;
-	unsigned int i;
-	struct omac1_test_vector *tv;
 
 	if (argc >= 3 && os_strcmp(argv[1], "NIST-KW-AE") == 0)
 		ret += test_nist_key_wrap_ae(argv[2]);
 	else if (argc >= 3 && os_strcmp(argv[1], "NIST-KW-AD") == 0)
 		ret += test_nist_key_wrap_ad(argv[2]);
 
-	ret += test_key_wrap();
-
 	test_aes_perf();
 
-	for (i = 0; i < ARRAY_SIZE(test_vectors); i++) {
-		tv = &test_vectors[i];
-		if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
-		    memcmp(result, tv->tag, 16) != 0) {
-			printf("OMAC1-AES-128 test vector %d failed\n", i);
-			ret++;
-		}
-
-		if (tv->msg_len > 1) {
-			const u8 *addr[2];
-			size_t len[2];
-
-			addr[0] = tv->msg;
-			len[0] = 1;
-			addr[1] = tv->msg + 1;
-			len[1] = tv->msg_len - 1;
-
-			if (omac1_aes_128_vector(tv->k, 2, addr, len,
-						 result) ||
-			    memcmp(result, tv->tag, 16) != 0) {
-				printf("OMAC1-AES-128(vector) test vector %d "
-				       "failed\n", i);
-				ret++;
-			}
-		}
-	}
-
-	ret += test_eax();
-
-	ret += test_cbc();
-
 	ret += test_gcm();
 
-	ret += test_siv();
-
 	if (ret)
 		printf("FAILED!\n");
 
diff --git a/tests/test-md5.c b/tests/test-md5.c
deleted file mode 100644
index b5246a4..0000000
--- a/tests/test-md5.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Test program for MD5 (test vectors from RFC 1321)
- * Copyright (c) 2006, 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 "crypto/crypto.h"
-
-int main(int argc, char *argv[])
-{
-	struct {
-		char *data;
-		char *hash;
-	} tests[] = {
-		{
-			"",
-			"\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
-			"\xe9\x80\x09\x98\xec\xf8\x42\x7e"
-		},
-		{
-			"a",
-			"\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
-			"\x31\xc3\x99\xe2\x69\x77\x26\x61"
-		},
-		{
-			"abc",
-			"\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
-			"\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
-		},
-		{
-			"message digest",
-			"\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
-			"\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
-		},
-		{
-			"abcdefghijklmnopqrstuvwxyz",
-			"\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
-			"\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
-		},
-		{
-			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-			"0123456789",
-			"\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
-			"\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
-		},
-		{
-			"12345678901234567890123456789012345678901234567890"
-			"123456789012345678901234567890",
-			"\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
-			"\xac\x49\xda\x2e\x21\x07\xb6\x7a"
-		}
-	};
-	unsigned int i;
-	u8 hash[16];
-	const u8 *addr[2];
-	size_t len[2];
-	int errors = 0;
-
-	for (i = 0; i < ARRAY_SIZE(tests); i++) {
-		printf("MD5 test case %d:", i);
-
-		addr[0] = (u8 *) tests[i].data;
-		len[0] = strlen(tests[i].data);
-		md5_vector(1, addr, len, hash);
-		if (memcmp(hash, tests[i].hash, 16) != 0) {
-			printf(" FAIL");
-			errors++;
-		} else
-			printf(" OK");
-
-		if (len[0]) {
-			addr[0] = (u8 *) tests[i].data;
-			len[0] = strlen(tests[i].data);
-			addr[1] = (u8 *) tests[i].data + 1;
-			len[1] = strlen(tests[i].data) - 1;
-			md5_vector(1, addr, len, hash);
-			if (memcmp(hash, tests[i].hash, 16) != 0) {
-				printf(" FAIL");
-				errors++;
-			} else
-				printf(" OK");
-		}
-
-		printf("\n");
-	}
-
-	return errors;
-}
diff --git a/tests/test-ms_funcs.c b/tests/test-ms_funcs.c
deleted file mode 100644
index b740bc9..0000000
--- a/tests/test-ms_funcs.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Test program for ms_funcs
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "crypto/ms_funcs.c"
-
-
-int main(int argc, char *argv[])
-{
-	/* Test vector from RFC2759 example */
-	char *username = "User";
-	char *password = "clientPass";
-	u8 auth_challenge[] = {
-		0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
-		0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
-	};
-	u8 peer_challenge[] = {
-		0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
-		0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
-	};
-	u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
-	u8 password_hash[] = {
-		0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
-		0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
-	};
-	u8 nt_response[] = {
-		0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
-		0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
-		0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
-	};
-	u8 password_hash_hash[] = {
-		0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
-		0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
-	};
-	u8 authenticator_response[] = {
-		0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
-		0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
-		0x93, 0x2C, 0xDA, 0x56
-	};
-	u8 master_key[] = {
-		0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
-		0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
-	};
-	u8 send_start_key[] = {
-		0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
-		0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
-	};
-	u8 buf[32];
-
-	int errors = 0;
-
-	printf("Testing ms_funcs.c\n");
-
-	if (challenge_hash(peer_challenge, auth_challenge,
-			   (u8 *) username, strlen(username),
-			   buf) ||
-	    memcmp(challenge, buf, sizeof(challenge)) != 0) {
-		printf("challenge_hash failed\n");
-		errors++;
-	}
-
-	if (nt_password_hash((u8 *) password, strlen(password), buf) ||
-	    memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
-		printf("nt_password_hash failed\n");
-		errors++;
-	}
-
-	if (generate_nt_response(auth_challenge, peer_challenge,
-				 (u8 *) username, strlen(username),
-				 (u8 *) password, strlen(password),
-				 buf) ||
-	    memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
-		printf("generate_nt_response failed\n");
-		errors++;
-	}
-
-	if (hash_nt_password_hash(password_hash, buf) ||
-	    memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
-		printf("hash_nt_password_hash failed\n");
-		errors++;
-	}
-
-	if (generate_authenticator_response((u8 *) password, strlen(password),
-					    peer_challenge, auth_challenge,
-					    (u8 *) username, strlen(username),
-					    nt_response, buf) ||
-	    memcmp(authenticator_response, buf, sizeof(authenticator_response))
-	    != 0) {
-		printf("generate_authenticator_response failed\n");
-		errors++;
-	}
-
-	if (get_master_key(password_hash_hash, nt_response, buf) ||
-	    memcmp(master_key, buf, sizeof(master_key)) != 0) {
-		printf("get_master_key failed\n");
-		errors++;
-	}
-
-	if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
-				    1, 1) ||
-	    memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
-		printf("get_asymetric_start_key failed\n");
-		errors++;
-	}
-
-	if (errors)
-		printf("FAILED! %d errors\n", errors);
-
-	return errors;
-}
diff --git a/tests/test-sha1.c b/tests/test-sha1.c
index c0aee38..3269d4d 100644
--- a/tests/test-sha1.c
+++ b/tests/test-sha1.c
@@ -10,364 +10,6 @@
 
 #include "common.h"
 #include "crypto/crypto.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-
-
-static int test_eap_fast(void)
-{
-	/* RFC 4851, Appendix B.1 */
-	const u8 pac_key[] = {
-		0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
-		0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
-		0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
-		0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
-	};
-	const u8 seed[] = {
-		0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
-		0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
-		0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
-		0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
-		0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
-		0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
-		0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
-		0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
-	};
-	const u8 master_secret[] = {
-		0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
-		0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
-		0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
-		0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
-		0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
-		0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2  
-	};
-	const u8 key_block[] = {
-		0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
-		0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
-		0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
-		0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
-		0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
-		0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
-		0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
-		0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
-		0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
-		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
-		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
-		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
-		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
-		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
-	};
-	const u8 sks[] = {
-		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
-		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
-		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
-		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
-		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
-	};
-	const u8 isk[] = {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
-	const u8 imck[] = {
-		0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
-		0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
-		0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
-		0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
-		0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
-		0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
-		0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
-		0x15, 0xEC, 0x57, 0x7B
-	};
-	const u8 msk[] = {
-		0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
-		0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
-		0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
-		0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
-		0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
-		0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
-		0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
-		0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
-	};
-	const u8 emsk[] = {
-		0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
-		0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
-		0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
-		0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
-		0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
-		0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
-		0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
-		0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
-	};
-	/* RFC 4851, Appendix B.2 */
-	u8 tlv[] = {
-		0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
-		0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
-		0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
-		0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
-		0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
-		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
-		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
-		0x05, 0xC5, 0x5B, 0xB7
-	};
-	const u8 compound_mac[] = {
-		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
-		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
-		0x05, 0xC5, 0x5B, 0xB7
-	};
-	u8 buf[512];
-	const u8 *simck, *cmk;
-	int errors = 0;
-
-	printf("EAP-FAST test cases\n");
-
-	printf("- T-PRF (SHA1) test case / master_secret\n");
-	sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash",
-		   seed, sizeof(seed), buf, sizeof(master_secret));
-	if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- PRF (TLS, SHA1/MD5) test case / key_block\n");
-	if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
-			     "key expansion", seed, sizeof(seed),
-			     buf, sizeof(key_block)) ||
-	    memcmp(key_block, buf, sizeof(key_block)) != 0) {
-		printf("PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- T-PRF (SHA1) test case / IMCK\n");
-	sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
-		   isk, sizeof(isk), buf, sizeof(imck));
-	if (memcmp(imck, buf, sizeof(imck)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	simck = imck;
-	cmk = imck + 40;
-
-	printf("- T-PRF (SHA1) test case / MSK\n");
-	sha1_t_prf(simck, 40, "Session Key Generating Function",
-		   (u8 *) "", 0, buf, sizeof(msk));
-	if (memcmp(msk, buf, sizeof(msk)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- T-PRF (SHA1) test case / EMSK\n");
-	sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
-		   (u8 *) "", 0, buf, sizeof(msk));
-	if (memcmp(emsk, buf, sizeof(emsk)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- Compound MAC test case\n");
-	memset(tlv + sizeof(tlv) - 20, 0, 20);
-	hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20);
-	if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac))
-	    != 0) {
-		printf("Compound MAC test - FAILED!\n");
-		errors++;
-	}
-
-	return errors;
-}
-
-
-static u8 key0[] =
-{
-	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-	0x0b, 0x0b, 0x0b, 0x0b
-};
-static u8 data0[] = "Hi There";
-static u8 prf0[] =
-{
-	0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
-	0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
-	0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
-	0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
-	0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
-	0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
-	0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
-	0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
-};
-
-static u8 key1[] = "Jefe";
-static u8 data1[] = "what do ya want for nothing?";
-static u8 prf1[] =
-{
-	0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
-	0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
-	0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
-	0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
-	0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
-	0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
-	0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
-	0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
-};
-
-
-static u8 key2[] =
-{
-	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-	0xaa, 0xaa, 0xaa, 0xaa
-};
-static u8 data2[] =
-{
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd
-};
-static u8 prf2[] =
-{
-	0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
-	0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
-	0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
-	0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
-	0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
-	0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
-	0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
-	0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
-};
-
-
-struct passphrase_test {
-	char *passphrase;
-	char *ssid;
-	char psk[32];
-};
-
-static struct passphrase_test passphrase_tests[] =
-{
-	{
-		"password",
-		"IEEE",
-		{
-			0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
-			0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
-			0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
-			0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
-		}
-	},
-	{
-		"ThisIsAPassword",
-		"ThisIsASSID",
-		{
-			0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
-			0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
-			0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
-			0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
-		}
-	},
-	{
-		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-		"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
-		{
-			0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
-			0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
-			0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
-			0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
-		}
-	},
-};
-
-#define NUM_PASSPHRASE_TESTS ARRAY_SIZE(passphrase_tests)
-
-
-struct rfc6070_test {
-	char *p;
-	char *s;
-	int c;
-	char dk[32];
-	size_t dk_len;
-};
-
-static struct rfc6070_test rfc6070_tests[] =
-{
-	{
-		"password",
-		"salt",
-		1,
-		{
-			0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
-			0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
-			0x2f, 0xe0, 0x37, 0xa6
-		},
-		20
-	},
-	{
-		"password",
-		"salt",
-		2,
-		{
-			0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
-			0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
-			0xd8, 0xde, 0x89, 0x57
-		},
-		20
-	},
-	{
-		"password",
-		"salt",
-		4096,
-		{
-			0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
-			0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
-			0x65, 0xa4, 0x29, 0xc1
-		},
-		20
-	},
-#if 0 /* This takes quite long to derive.. */
-	{
-		"password",
-		"salt",
-		16777216,
-		{
-			0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
-			0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
-			0x26, 0x34, 0xe9, 0x84
-		},
-		20
-	},
-#endif
-	{
-		"passwordPASSWORDpassword",
-		"saltSALTsaltSALTsaltSALTsaltSALTsalt",
-		4096,
-		{
-			0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
-			0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
-			0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
-			0x38
-		},
-		25
-	},
-#if 0 /* \0 not currently supported in passphrase parameters.. */
-	{
-		"pass\0word",
-		"sa\0lt",
-		4096,
-		{
-			0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
-			0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
-		},
-		16
-	},
-#endif
-};
-
-#define NUM_RFC6070_TESTS ARRAY_SIZE(rfc6070_tests)
 
 
 static int cavp_shavs(const char *fname)
@@ -466,69 +108,7 @@
 
 int main(int argc, char *argv[])
 {
-	u8 res[512];
 	int ret = 0;
-	unsigned int i;
-
-	printf("PRF-SHA1 test cases:\n");
-
-	sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
-		 res, sizeof(prf0));
-	if (memcmp(res, prf0, sizeof(prf0)) == 0)
-		printf("Test case 0 - OK\n");
-	else {
-		printf("Test case 0 - FAILED!\n");
-		ret++;
-	}
-
-	sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
-		 res, sizeof(prf1));
-	if (memcmp(res, prf1, sizeof(prf1)) == 0)
-		printf("Test case 1 - OK\n");
-	else {
-		printf("Test case 1 - FAILED!\n");
-		ret++;
-	}
-
-	sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
-		 res, sizeof(prf2));
-	if (memcmp(res, prf2, sizeof(prf2)) == 0)
-		printf("Test case 2 - OK\n");
-	else {
-		printf("Test case 2 - FAILED!\n");
-		ret++;
-	}
-
-	ret += test_eap_fast();
-
-	printf("PBKDF2-SHA1 Passphrase test cases:\n");
-	for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
-		u8 psk[32];
-		struct passphrase_test *test = &passphrase_tests[i];
-		pbkdf2_sha1(test->passphrase,
-			    (const u8 *) test->ssid, strlen(test->ssid),
-			    4096, psk, 32);
-		if (memcmp(psk, test->psk, 32) == 0)
-			printf("Test case %d - OK\n", i);
-		else {
-			printf("Test case %d - FAILED!\n", i);
-			ret++;
-		}
-	}
-
-	printf("PBKDF2-SHA1 test cases (RFC 6070):\n");
-	for (i = 0; i < NUM_RFC6070_TESTS; i++) {
-		u8 dk[25];
-		struct rfc6070_test *test = &rfc6070_tests[i];
-		pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
-			    test->c, dk, test->dk_len);
-		if (memcmp(dk, test->dk, test->dk_len) == 0)
-			printf("Test case %d - OK\n", i);
-		else {
-			printf("Test case %d - FAILED!\n", i);
-			ret++;
-		}
-	}
 
 	if (cavp_shavs("CAVP/SHA1ShortMsg.rsp"))
 		ret++;
diff --git a/tests/test-sha256.c b/tests/test-sha256.c
index ade0f2e..741351a 100644
--- a/tests/test-sha256.c
+++ b/tests/test-sha256.c
@@ -9,238 +9,8 @@
 #include "includes.h"
 
 #include "common.h"
-#include "crypto/sha256.h"
 #include "crypto/crypto.h"
 
-struct {
-	char *data;
-	u8 hash[32];
-} tests[] = {
-	{
-		"abc",
-		{
-			0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
-			0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
-			0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
-			0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
-		}
-	},
-	{
-		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		{
-			0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
-			0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
-			0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
-			0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
-		}
-	}
-};
-
-struct hmac_test {
-	u8 key[80];
-	size_t key_len;
-	u8 data[128];
-	size_t data_len;
-	u8 hash[32];
-} hmac_tests[] = {
-	/* draft-ietf-ipsec-ciph-sha-256-01.txt */
-	{
-		{
-			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
-		},
-		32,
-		"abc", 3,
-		{
-			0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
-			0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
-			0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
-			0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
-		}
-	},
-	{
-		{
-			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
-		},
-		32,
-		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		56,
-		{
-			0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
-			0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
-			0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
-			0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
-		}
-	},
-	{
-		{
-			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
-		},
-		32,
-		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-		112,
-		{
-			0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
-			0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
-			0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
-			0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
-		}
-	},
-	{
-		{
-			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-			0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
-		},
-		32,
-		"Hi There",
-		8,
-		{
-			0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
-			0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
-			0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
-			0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
-		}
-	},
-	{
-		"Jefe",
-		4,
-		"what do ya want for nothing?",
-		28,
-		{
-			0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
-			0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
-			0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
-			0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
-		}
-	},
-	{
-		{
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
-		},
-		32,
-		{
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-			0xdd, 0xdd
-		},
-		50,
-		{
-			0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
-			0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
-			0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
-			0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
-		}
-	},
-	{
-		{
-			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
-			0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-			0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
-			0x21, 0x22, 0x23, 0x24, 0x25
-		},
-		37,
-		{
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
-			0xcd, 0xcd
-		},
-		50,
-		{
-			0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
-			0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
-			0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
-			0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
-		}
-	},
-	{
-		{
-			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-			0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
-		},
-		32,
-		"Test With Truncation",
-		20,
-		{
-			0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
-			0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
-			0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
-			0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
-		}
-	},
-	{
-		{
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
-		},
-		80,
-		"Test Using Larger Than Block-Size Key - Hash Key First",
-		54,
-		{
-			0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
-			0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
-			0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
-			0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
-		}
-	},
-	{
-		{
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-			0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
-		},
-		80,
-		"Test Using Larger Than Block-Size Key and Larger Than One "
-		"Block-Size Data",
-		73,
-		{
-			0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
-			0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
-			0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
-			0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
-		}
-	}
-};
-
 
 static int cavp_shavs(const char *fname)
 {
@@ -338,83 +108,8 @@
 
 int main(int argc, char *argv[])
 {
-
-	unsigned int i;
-	u8 hash[32];
-	const u8 *addr[2];
-	size_t len[2];
 	int errors = 0;
 
-	for (i = 0; i < ARRAY_SIZE(tests); i++) {
-		printf("SHA256 test case %d:", i + 1);
-
-		addr[0] = (u8 *) tests[i].data;
-		len[0] = strlen(tests[i].data);
-		sha256_vector(1, addr, len, hash);
-		if (memcmp(hash, tests[i].hash, 32) != 0) {
-			printf(" FAIL");
-			errors++;
-		} else
-			printf(" OK");
-
-		if (len[0]) {
-			addr[0] = (u8 *) tests[i].data;
-			len[0] = 1;
-			addr[1] = (u8 *) tests[i].data + 1;
-			len[1] = strlen(tests[i].data) - 1;
-			sha256_vector(2, addr, len, hash);
-			if (memcmp(hash, tests[i].hash, 32) != 0) {
-				printf(" FAIL");
-				errors++;
-			} else
-				printf(" OK");
-		}
-
-		printf("\n");
-	}
-
-	for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
-		struct hmac_test *t = &hmac_tests[i];
-		printf("HMAC-SHA256 test case %d:", i + 1);
-
-		hmac_sha256(t->key, t->key_len, t->data, t->data_len, hash);
-		if (memcmp(hash, t->hash, 32) != 0) {
-			printf(" FAIL");
-			errors++;
-		} else
-			printf(" OK");
-
-		addr[0] = t->data;
-		len[0] = t->data_len;
-		hmac_sha256_vector(t->key, t->key_len, 1, addr, len, hash);
-		if (memcmp(hash, t->hash, 32) != 0) {
-			printf(" FAIL");
-			errors++;
-		} else
-			printf(" OK");
-
-		if (len[0]) {
-			addr[0] = t->data;
-			len[0] = 1;
-			addr[1] = t->data + 1;
-			len[1] = t->data_len - 1;
-			hmac_sha256_vector(t->key, t->key_len, 2, addr, len,
-					   hash);
-			if (memcmp(hash, t->hash, 32) != 0) {
-				printf(" FAIL");
-				errors++;
-			} else
-				printf(" OK");
-		}
-
-		printf("\n");
-	}
-
-	printf("Test IEEE 802.11r KDF\n");
-	sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
-		   hash, sizeof(hash));
-	/* TODO: add proper test case for this */
-
 	if (cavp_shavs("CAVP/SHA256ShortMsg.rsp"))
 		errors++;
 	if (cavp_shavs("CAVP/SHA256LongMsg.rsp"))
diff --git a/tests/wnm-fuzzer/Makefile b/tests/wnm-fuzzer/Makefile
new file mode 100644
index 0000000..dede75b
--- /dev/null
+++ b/tests/wnm-fuzzer/Makefile
@@ -0,0 +1,91 @@
+all: wnm-fuzzer
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+SRC=../../src
+
+CFLAGS += -I$(SRC)
+CFLAGS += -DCONFIG_WNM
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_GAS
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DIEEE8021X_EAPOL
+
+$(SRC)/utils/libutils.a:
+	$(MAKE) -C $(SRC)/utils
+
+$(SRC)/common/libcommon.a:
+	$(MAKE) -C $(SRC)/common
+
+$(SRC)/crypto/libcrypto.a:
+	$(MAKE) -C $(SRC)/crypto
+
+$(SRC)/tls/libtls.a:
+	$(MAKE) -C $(SRC)/tls
+
+$(SRC)/rsn_supp/librsn_supp.a:
+	$(MAKE) -C $(SRC)/rsn_supp
+
+$(SRC)/eapol_supp/libeapol_supp.a:
+	$(MAKE) -C $(SRC)/eapol_supp
+
+$(SRC)/eap_peer/libeap_peer.a:
+	$(MAKE) -C $(SRC)/eap_peer
+
+$(SRC)/eap_common/libeap_common.a:
+	$(MAKE) -C $(SRC)/eap_common
+
+$(SRC)/l2_packet/libl2_packet.a:
+	$(MAKE) -C $(SRC)/l2_packet
+
+LIBS += $(SRC)/common/libcommon.a
+LIBS += $(SRC)/crypto/libcrypto.a
+LIBS += $(SRC)/tls/libtls.a
+LIBS += $(SRC)/rsn_supp/librsn_supp.a
+LIBS += $(SRC)/eapol_supp/libeapol_supp.a
+LIBS += $(SRC)/eap_peer/libeap_peer.a
+LIBS += $(SRC)/eap_common/libeap_common.a
+LIBS += $(SRC)/l2_packet/libl2_packet.a
+LIBS += $(SRC)/utils/libutils.a
+
+ELIBS += $(SRC)/crypto/libcrypto.a
+ELIBS += $(SRC)/tls/libtls.a
+
+CFLAGS += -I$(SRC)/utils
+OBJS += ../../wpa_supplicant/wnm_sta.o
+OBJS += ../../wpa_supplicant/bss.o
+OBJS += ../../wpa_supplicant/scan.o
+OBJS += ../../wpa_supplicant/notify.o
+OBJS += ../../wpa_supplicant/wpa_supplicant.o
+OBJS += ../../wpa_supplicant/config.o
+OBJS += ../../wpa_supplicant/config_file.o
+OBJS += ../../wpa_supplicant/blacklist.o
+OBJS += ../../wpa_supplicant/events.o
+OBJS += ../../wpa_supplicant/wpas_glue.o
+OBJS += ../../wpa_supplicant/wmm_ac.o
+OBJS += ../../wpa_supplicant/eap_register.o
+OBJS += ../../wpa_supplicant/gas_query.o
+OBJS += ../../wpa_supplicant/offchannel.o
+OBJS += ../../wpa_supplicant/interworking.o
+OBJS += ../../wpa_supplicant/hs20_supplicant.o
+OBJS += $(SRC)/drivers/drivers.o
+OBJS += $(SRC)/drivers/driver_common.o
+
+wnm-fuzzer: wnm-fuzzer.o $(OBJS) $(LIBS)
+	$(LDO) $(LDFLAGS) -o $@ $^ $(LIBS) $(ELIBS)
+
+clean:
+	$(MAKE) -C $(SRC) clean
+	rm -f wnm-fuzzer *~ *.o *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/tests/wnm-fuzzer/bss-tm-req.dat b/tests/wnm-fuzzer/bss-tm-req.dat
new file mode 100644
index 0000000..14510bb
--- /dev/null
+++ b/tests/wnm-fuzzer/bss-tm-req.dat
Binary files differ
diff --git a/tests/wnm-fuzzer/wnm-fuzzer.c b/tests/wnm-fuzzer/wnm-fuzzer.c
new file mode 100644
index 0000000..8efa311
--- /dev/null
+++ b/tests/wnm-fuzzer/wnm-fuzzer.c
@@ -0,0 +1,106 @@
+/*
+ * wpa_supplicant - WNM fuzzer
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_i.h"
+#include "../../wpa_supplicant/wpa_supplicant_i.h"
+#include "../../wpa_supplicant/bss.h"
+#include "../../wpa_supplicant/wnm_sta.h"
+
+
+struct arg_ctx {
+	const char *fname;
+	struct wpa_supplicant wpa_s;
+	struct wpa_bss bss;
+	struct wpa_driver_ops driver;
+	struct wpa_sm wpa;
+};
+
+
+static void test_send_wnm(void *eloop_data, void *user_ctx)
+{
+	struct arg_ctx *ctx = eloop_data;
+	char *data;
+	size_t len;
+	struct ieee80211_mgmt *mgmt;
+
+	wpa_printf(MSG_INFO, "wnm-fuzzer: Send '%s'", ctx->fname);
+
+	data = os_readfile(ctx->fname, &len);
+	if (!data) {
+		wpa_printf(MSG_ERROR, "Could not read '%s'", ctx->fname);
+		goto out;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "fuzzer - WNM", data, len);
+
+	mgmt = (struct ieee80211_mgmt *) data;
+	ieee802_11_rx_wnm_action(&ctx->wpa_s, mgmt, len);
+
+out:
+	os_free(data);
+	eloop_terminate();
+}
+
+
+static int init_wpa(struct arg_ctx *ctx)
+{
+	ctx->wpa_s.wpa_state = WPA_COMPLETED;
+	os_memcpy(ctx->wpa_s.bssid, "\x02\x00\x00\x00\x03\x00", ETH_ALEN);
+	ctx->wpa_s.current_bss = &ctx->bss;
+	ctx->wpa_s.driver = &ctx->driver;
+	ctx->wpa_s.wpa = &ctx->wpa;
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct arg_ctx ctx;
+	int ret = -1;
+
+	if (argc < 2) {
+		printf("usage: %s <file>\n", argv[0]);
+		return -1;
+	}
+
+	if (os_program_init())
+		return -1;
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	os_memset(&ctx, 0, sizeof(ctx));
+	ctx.fname = argv[1];
+	if (init_wpa(&ctx))
+		goto fail;
+
+	eloop_register_timeout(0, 0, test_send_wnm, &ctx, NULL);
+
+	wpa_printf(MSG_DEBUG, "Starting eloop");
+	eloop_run();
+	wpa_printf(MSG_DEBUG, "eloop done");
+
+	ret = 0;
+fail:
+	eloop_destroy();
+	os_program_deinit();
+
+	return ret;
+}
diff --git a/tests/wnm-fuzzer/wnm-notif.dat b/tests/wnm-fuzzer/wnm-notif.dat
new file mode 100644
index 0000000..c234d3a
--- /dev/null
+++ b/tests/wnm-fuzzer/wnm-notif.dat
Binary files differ
diff --git a/wlantest/bip.c b/wlantest/bip.c
index d9a52e9..bda8036 100644
--- a/wlantest/bip.c
+++ b/wlantest/bip.c
@@ -14,8 +14,8 @@
 #include "wlantest.h"
 
 
-u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid,
-		 size_t *prot_len)
+u8 * bip_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
+		 u8 *ipn, int keyid, size_t *prot_len)
 {
 	u8 *prot, *pos, *buf;
 	u8 mic[16];
@@ -23,19 +23,19 @@
 	struct ieee80211_hdr *hdr;
 	size_t plen;
 
-	plen = len + 18;
+	plen = len + igtk_len == 32 ? 26 : 18;
 	prot = os_malloc(plen);
 	if (prot == NULL)
 		return NULL;
 	os_memcpy(prot, frame, len);
 	pos = prot + len;
 	*pos++ = WLAN_EID_MMIE;
-	*pos++ = 16;
+	*pos++ = igtk_len == 32 ? 24 : 16;
 	WPA_PUT_LE16(pos, keyid);
 	pos += 2;
 	os_memcpy(pos, ipn, 6);
 	pos += 6;
-	os_memset(pos, 0, 8); /* MIC */
+	os_memset(pos, 0, igtk_len == 32 ? 16 : 8); /* MIC */
 
 	buf = os_malloc(plen + 20 - 24);
 	if (buf == NULL) {
@@ -59,8 +59,8 @@
 	}
 	os_free(buf);
 
-	os_memcpy(pos, mic, 8);
-	wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
+	os_memcpy(pos, mic, igtk_len == 32 ? 16 : 8);
+	wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, igtk_len == 32 ? 16 : 8);
 
 	*prot_len = plen;
 	return prot;
diff --git a/wlantest/bss.c b/wlantest/bss.c
index 0f773bf..61e2960 100644
--- a/wlantest/bss.c
+++ b/wlantest/bss.c
@@ -277,7 +277,7 @@
 		   " proto=%s%s%s%s"
 		   "pairwise=%s%s%s%s%s%s%s"
 		   "group=%s%s%s%s%s%s%s%s%s"
-		   "mgmt_group_cipher=%s"
+		   "mgmt_group_cipher=%s%s%s%s%s"
 		   "key_mgmt=%s%s%s%s%s%s%s%s%s"
 		   "rsn_capab=%s%s%s%s%s",
 		   MAC2STR(bss->bssid),
@@ -303,8 +303,15 @@
 		   bss->group_cipher & WPA_CIPHER_CCMP_256 ? "CCMP-256 " : "",
 		   bss->group_cipher & WPA_CIPHER_GCMP ? "GCMP " : "",
 		   bss->group_cipher & WPA_CIPHER_GCMP_256 ? "GCMP-256 " : "",
-		   bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ? "BIP " :
-		   "N/A ",
+		   bss->mgmt_group_cipher == 0 ? "N/A " : "",
+		   bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ?
+		   "BIP " : "",
+		   bss->mgmt_group_cipher & WPA_CIPHER_BIP_GMAC_128 ?
+		   "BIP-GMAC-128 " : "",
+		   bss->mgmt_group_cipher & WPA_CIPHER_BIP_GMAC_256 ?
+		   "BIP-GMAC-256 " : "",
+		   bss->mgmt_group_cipher & WPA_CIPHER_BIP_CMAC_256 ?
+		   "BIP-CMAC-256 " : "",
 		   bss->key_mgmt == 0 ? "N/A " : "",
 		   bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "",
 		   bss->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "",
diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c
index 2b6d453..7de0a8a 100644
--- a/wlantest/ctrl.c
+++ b/wlantest/ctrl.c
@@ -1,6 +1,6 @@
 /*
  * wlantest control interface
- * Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -906,6 +906,15 @@
 	if (cipher & WPA_CIPHER_AES_128_CMAC)
 		pos += os_snprintf(pos, end - pos, "%sBIP",
 				   pos == buf ? "" : " ");
+	if (cipher & WPA_CIPHER_BIP_GMAC_128)
+		pos += os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
+				   pos == buf ? "" : " ");
+	if (cipher & WPA_CIPHER_BIP_GMAC_256)
+		pos += os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
+				   pos == buf ? "" : " ");
+	if (cipher & WPA_CIPHER_BIP_CMAC_256)
+		pos += os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
+				   pos == buf ? "" : " ");
 }
 
 
@@ -945,6 +954,9 @@
 	if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
 		pos += os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
 				   pos == buf ? "" : " ");
+	if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		pos += os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
+				   pos == buf ? "" : " ");
 }
 
 
diff --git a/wlantest/inject.c b/wlantest/inject.c
index 22a9e2a..ed25033 100644
--- a/wlantest/inject.c
+++ b/wlantest/inject.c
@@ -1,6 +1,6 @@
 /*
  * wlantest frame injection
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -82,17 +82,18 @@
 			       u8 *frame, size_t len, int incorrect_key)
 {
 	u8 *prot;
-	u8 dummy[16];
+	u8 dummy[32];
 	int ret;
 	size_t plen;
 
-	if (!bss->igtk_set[bss->igtk_idx])
+	if (!bss->igtk_len[bss->igtk_idx])
 		return -1;
 
 	os_memset(dummy, 0x11, sizeof(dummy));
 	inc_byte_array(bss->ipn[bss->igtk_idx], 6);
 
 	prot = bip_protect(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
+			   bss->igtk_len[bss->igtk_idx],
 			   frame, len, bss->ipn[bss->igtk_idx],
 			   bss->igtk_idx, &plen);
 	if (prot == NULL)
@@ -247,11 +248,11 @@
 				     frame, len, hdrlen, qos, pn, 0,
 				     &crypt_len);
 	else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
-		crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+		crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk,
 				     frame, len, hdrlen, qos, pn, 0,
 				     &crypt_len);
 	else
-		crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
+		crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk,
 				     frame, len, hdrlen, qos, pn, 0,
 				     &crypt_len);
 
@@ -300,7 +301,7 @@
 	     prot == WLANTEST_INJECT_INCORRECT_KEY) && bss) {
 		if (!sta &&
 		    ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		      !bss->igtk_set[bss->igtk_idx]) ||
+		      !bss->igtk_len[bss->igtk_idx]) ||
 		     (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
 		      !bss->gtk_len[bss->gtk_idx]))) {
 			wpa_printf(MSG_INFO, "No GTK/IGTK known for "
@@ -323,7 +324,7 @@
 			    bss->gtk_len[bss->gtk_idx])
 				protect = 1;
 			if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-			    bss->igtk_set[bss->igtk_idx])
+			    bss->igtk_len[bss->igtk_idx])
 				protect = 1;
 		}
 	}
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
index 3c500d6..4c55e7d 100644
--- a/wlantest/rx_data.c
+++ b/wlantest/rx_data.c
@@ -1,6 +1,6 @@
 /*
  * Received Data frame processing
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -107,21 +107,21 @@
 		decrypted = NULL;
 		if ((pairwise_cipher == WPA_CIPHER_CCMP ||
 		     pairwise_cipher == 0) && tk_len == 16) {
-			decrypted = ccmp_decrypt(ptk->ptk.tk1, hdr, data,
+			decrypted = ccmp_decrypt(ptk->ptk.tk, hdr, data,
 						 data_len, decrypted_len);
 		} else if ((pairwise_cipher == WPA_CIPHER_CCMP_256 ||
 			    pairwise_cipher == 0) && tk_len == 32) {
-			decrypted = ccmp_256_decrypt(ptk->ptk.tk1, hdr, data,
+			decrypted = ccmp_256_decrypt(ptk->ptk.tk, hdr, data,
 						     data_len, decrypted_len);
 		} else if ((pairwise_cipher == WPA_CIPHER_GCMP ||
 			    pairwise_cipher == WPA_CIPHER_GCMP_256 ||
 			    pairwise_cipher == 0) &&
 			   (tk_len == 16 || tk_len == 32)) {
-			decrypted = gcmp_decrypt(ptk->ptk.tk1, tk_len, hdr,
+			decrypted = gcmp_decrypt(ptk->ptk.tk, tk_len, hdr,
 						 data, data_len, decrypted_len);
 		} else if ((pairwise_cipher == WPA_CIPHER_TKIP ||
 			    pairwise_cipher == 0) && tk_len == 32) {
-			decrypted = tkip_decrypt(ptk->ptk.tk1, hdr, data,
+			decrypted = tkip_decrypt(ptk->ptk.tk, hdr, data,
 						 data_len, decrypted_len);
 		}
 		if (decrypted) {
@@ -411,19 +411,19 @@
 		else
 			decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen);
 	} else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) {
-		decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
+		decrypted = tkip_decrypt(sta->ptk.tk, hdr, data, len, &dlen);
 	} else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) {
 		decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
 	} else if (sta->ptk_set) {
 		if (sta->pairwise_cipher == WPA_CIPHER_CCMP_256)
-			decrypted = ccmp_256_decrypt(sta->ptk.tk1, hdr, data,
+			decrypted = ccmp_256_decrypt(sta->ptk.tk, hdr, data,
 						     len, &dlen);
 		else if (sta->pairwise_cipher == WPA_CIPHER_GCMP ||
 			 sta->pairwise_cipher == WPA_CIPHER_GCMP_256)
-			decrypted = gcmp_decrypt(sta->ptk.tk1, sta->tk_len,
+			decrypted = gcmp_decrypt(sta->ptk.tk, sta->tk_len,
 						 hdr, data, len, &dlen);
 		else
-			decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len,
+			decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data, len,
 						 &dlen);
 	} else {
 		decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data,
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index 13510ef..04ea6ac 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -1,6 +1,6 @@
 /*
  * Received Data frame processing for EAPOL messages
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -31,14 +31,15 @@
 }
 
 
-static int check_mic(const u8 *kck, int akmp, int ver, const u8 *data,
-		     size_t len)
+static int check_mic(const u8 *kck, size_t kck_len, int akmp, int ver,
+		     const u8 *data, size_t len)
 {
 	u8 *buf;
 	int ret = -1;
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
-	u8 rx_mic[16];
+	u8 rx_mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+	size_t mic_len = 16;
 
 	buf = os_malloc(len);
 	if (buf == NULL)
@@ -47,11 +48,12 @@
 	hdr = (struct ieee802_1x_hdr *) buf;
 	key = (struct wpa_eapol_key *) (hdr + 1);
 
-	os_memcpy(rx_mic, key->key_mic, 16);
-	os_memset(key->key_mic, 0, 16);
+	os_memcpy(rx_mic, key->key_mic, mic_len);
+	os_memset(key->key_mic, 0, mic_len);
 
-	if (wpa_eapol_key_mic(kck, akmp, ver, buf, len, key->key_mic) == 0 &&
-	    os_memcmp(rx_mic, key->key_mic, 16) == 0)
+	if (wpa_eapol_key_mic(kck, kck_len, akmp, ver, buf, len,
+			      key->key_mic) == 0 &&
+	    os_memcmp(rx_mic, key->key_mic, mic_len) == 0)
 		ret = 0;
 
 	os_free(buf);
@@ -97,16 +99,12 @@
 		   struct wlantest_pmk *pmk)
 {
 	struct wpa_ptk ptk;
-	size_t ptk_len;
 
-	ptk_len = wpa_cipher_key_len(sta->pairwise_cipher) + 32;
-
-	wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
-		       "Pairwise key expansion",
-		       bss->bssid, sta->addr, sta->anonce, sta->snonce,
-		       (u8 *) &ptk, ptk_len,
-		       wpa_key_mgmt_sha256(sta->key_mgmt));
-	if (check_mic(ptk.kck, sta->key_mgmt, ver, data, len) < 0)
+	if (wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
+			   "Pairwise key expansion",
+			   bss->bssid, sta->addr, sta->anonce, sta->snonce,
+			   &ptk, sta->key_mgmt, sta->pairwise_cipher) < 0 ||
+	    check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data, len) < 0)
 		return -1;
 
 	sta->tk_len = wpa_cipher_key_len(sta->pairwise_cipher);
@@ -120,22 +118,20 @@
 		 */
 		add_note(wt, MSG_DEBUG, "Derived PTK during rekeying");
 		os_memcpy(&sta->tptk, &ptk, sizeof(ptk));
-		wpa_hexdump(MSG_DEBUG, "TPTK:KCK", sta->tptk.kck, 16);
-		wpa_hexdump(MSG_DEBUG, "TPTK:KEK", sta->tptk.kek, 16);
-		wpa_hexdump(MSG_DEBUG, "TPTK:TK1", sta->tptk.tk1, 16);
-		if (ptk_len > 48)
-			wpa_hexdump(MSG_DEBUG, "TPTK:TK2", sta->tptk.u.tk2,
-				    16);
+		wpa_hexdump(MSG_DEBUG, "TPTK:KCK",
+			    sta->tptk.kck, sta->tptk.kck_len);
+		wpa_hexdump(MSG_DEBUG, "TPTK:KEK",
+			    sta->tptk.kek, sta->tptk.kek_len);
+		wpa_hexdump(MSG_DEBUG, "TPTK:TK",
+			    sta->tptk.tk, sta->tptk.tk_len);
 		sta->tptk_set = 1;
 		return 0;
 	}
 	add_note(wt, MSG_DEBUG, "Derived new PTK");
 	os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
-	wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
-	wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
-	wpa_hexdump(MSG_DEBUG, "PTK:TK1", sta->ptk.tk1, 16);
-	if (ptk_len > 48)
-		wpa_hexdump(MSG_DEBUG, "PTK:TK2", sta->ptk.u.tk2, 16);
+	wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, sta->ptk.kck_len);
+	wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, sta->ptk.kek_len);
+	wpa_hexdump(MSG_DEBUG, "PTK:TK", sta->ptk.tk, sta->ptk.tk_len);
 	sta->ptk_set = 1;
 	os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
 	os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
@@ -169,8 +165,8 @@
 
 		wpa_debug_level = MSG_WARNING;
 		dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
-			if (check_mic(ptk->ptk.kck, sta->key_mgmt, ver, data,
-				      len) < 0)
+			if (check_mic(ptk->ptk.kck, ptk->ptk.kck_len,
+				      sta->key_mgmt, ver, data, len) < 0)
 				continue;
 			wpa_printf(MSG_INFO, "Pre-set PTK matches for STA "
 				   MACSTR " BSSID " MACSTR,
@@ -179,12 +175,12 @@
 			ptk->ptk_len = 32 +
 				wpa_cipher_key_len(sta->pairwise_cipher);
 			os_memcpy(&sta->ptk, &ptk->ptk, sizeof(ptk->ptk));
-			wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
-			wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
-			wpa_hexdump(MSG_DEBUG, "PTK:TK1", sta->ptk.tk1, 16);
-			if (ptk->ptk_len > 48)
-				wpa_hexdump(MSG_DEBUG, "PTK:TK2",
-					    sta->ptk.u.tk2, 16);
+			wpa_hexdump(MSG_DEBUG, "PTK:KCK",
+				    sta->ptk.kck, sta->ptk.kck_len);
+			wpa_hexdump(MSG_DEBUG, "PTK:KEK",
+				    sta->ptk.kek, sta->ptk.kek_len);
+			wpa_hexdump(MSG_DEBUG, "PTK:TK",
+				    sta->ptk.tk, sta->ptk.tk_len);
 			sta->ptk_set = 1;
 			os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
 			os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
@@ -204,6 +200,7 @@
 	const struct ieee802_1x_hdr *eapol;
 	const struct wpa_eapol_key *hdr;
 	const u8 *key_data, *kck;
+	size_t kck_len;
 	u16 key_info, key_data_len;
 	struct wpa_eapol_ie_parse ie;
 
@@ -238,13 +235,15 @@
 	}
 
 	kck = sta->ptk.kck;
+	kck_len = sta->ptk.kck_len;
 	if (sta->tptk_set) {
 		add_note(wt, MSG_DEBUG,
 			 "Use TPTK for validation EAPOL-Key MIC");
 		kck = sta->tptk.kck;
+		kck_len = sta->tptk.kck_len;
 	}
-	if (check_mic(kck, sta->key_mgmt, key_info & WPA_KEY_INFO_TYPE_MASK,
-		      data, len) < 0) {
+	if (check_mic(kck, kck_len, sta->key_mgmt,
+		      key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
 		add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
 		return;
 	}
@@ -371,10 +370,13 @@
 }
 
 
-static u8 * decrypt_eapol_key_data(struct wlantest *wt, const u8 *kek, u16 ver,
+static u8 * decrypt_eapol_key_data(struct wlantest *wt, const u8 *kek,
+				   size_t kek_len, u16 ver,
 				   const struct wpa_eapol_key *hdr,
 				   size_t *len)
 {
+	if (kek_len != 16)
+		return NULL;
 	switch (ver) {
 	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
 		return decrypt_eapol_key_data_rc4(wt, kek, hdr, len);
@@ -464,7 +466,30 @@
 				wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8,
 					    16);
 				os_memcpy(bss->igtk[id], ie.igtk + 8, 16);
-				bss->igtk_set[id] = 1;
+				bss->igtk_len[id] = 16;
+				ipn = ie.igtk + 2;
+				bss->ipn[id][0] = ipn[5];
+				bss->ipn[id][1] = ipn[4];
+				bss->ipn[id][2] = ipn[3];
+				bss->ipn[id][3] = ipn[2];
+				bss->ipn[id][4] = ipn[1];
+				bss->ipn[id][5] = ipn[0];
+				bss->igtk_idx = id;
+			}
+		} else if (ie.igtk_len == 40) {
+			u16 id;
+			id = WPA_GET_LE16(ie.igtk);
+			if (id > 5) {
+				add_note(wt, MSG_INFO,
+					 "Unexpected IGTK KeyID %u", id);
+			} else {
+				const u8 *ipn;
+				add_note(wt, MSG_DEBUG, "IGTK KeyID %u", id);
+				wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6);
+				wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8,
+					    32);
+				os_memcpy(bss->igtk[id], ie.igtk + 8, 32);
+				bss->igtk_len[id] = 32;
 				ipn = ie.igtk + 2;
 				bss->ipn[id][0] = ipn[5];
 				bss->ipn[id][1] = ipn[4];
@@ -490,6 +515,7 @@
 	const struct ieee802_1x_hdr *eapol;
 	const struct wpa_eapol_key *hdr;
 	const u8 *key_data, *kck, *kek;
+	size_t kck_len, kek_len;
 	int recalc = 0;
 	u16 key_info, ver;
 	u8 *decrypted_buf = NULL;
@@ -528,15 +554,19 @@
 	}
 
 	kek = sta->ptk.kek;
+	kek_len = sta->ptk.kek_len;
 	kck = sta->ptk.kck;
+	kck_len = sta->ptk.kck_len;
 	if (sta->tptk_set) {
 		add_note(wt, MSG_DEBUG,
 			 "Use TPTK for validation EAPOL-Key MIC");
 		kck = sta->tptk.kck;
+		kck_len = sta->tptk.kck_len;
 		kek = sta->tptk.kek;
+		kek_len = sta->tptk.kek_len;
 	}
-	if (check_mic(kck, sta->key_mgmt, key_info & WPA_KEY_INFO_TYPE_MASK,
-		      data, len) < 0) {
+	if (check_mic(kck, kck_len, sta->key_mgmt,
+		      key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
 		add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
 		return;
 	}
@@ -551,8 +581,8 @@
 		decrypted_len = WPA_GET_BE16(hdr->key_data_length);
 	} else {
 		ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-		decrypted_buf = decrypt_eapol_key_data(wt, kek, ver, hdr,
-						       &decrypted_len);
+		decrypted_buf = decrypt_eapol_key_data(wt, kek, kek_len, ver,
+						       hdr, &decrypted_len);
 		if (decrypted_buf == NULL) {
 			add_note(wt, MSG_INFO,
 				 "Failed to decrypt EAPOL-Key Key Data");
@@ -651,6 +681,7 @@
 	const struct wpa_eapol_key *hdr;
 	u16 key_info;
 	const u8 *kck;
+	size_t kck_len;
 
 	wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
 		   MAC2STR(src), MAC2STR(dst));
@@ -676,13 +707,15 @@
 	}
 
 	kck = sta->ptk.kck;
+	kck_len = sta->ptk.kck_len;
 	if (sta->tptk_set) {
 		add_note(wt, MSG_DEBUG,
 			 "Use TPTK for validation EAPOL-Key MIC");
 		kck = sta->tptk.kck;
+		kck_len = sta->tptk.kck_len;
 	}
-	if (check_mic(kck, sta->key_mgmt, key_info & WPA_KEY_INFO_TYPE_MASK,
-		      data, len) < 0) {
+	if (check_mic(kck, kck_len, sta->key_mgmt,
+		      key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
 		add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC");
 		return;
 	}
@@ -729,7 +762,7 @@
 	}
 
 	if (sta->ptk_set &&
-	    check_mic(sta->ptk.kck, sta->key_mgmt,
+	    check_mic(sta->ptk.kck, sta->ptk.kck_len, sta->key_mgmt,
 		      key_info & WPA_KEY_INFO_TYPE_MASK,
 		      data, len) < 0) {
 		add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 1/2 MIC");
@@ -743,8 +776,8 @@
 		return;
 	}
 	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-	decrypted = decrypt_eapol_key_data(wt, sta->ptk.kek, ver, hdr,
-					   &decrypted_len);
+	decrypted = decrypt_eapol_key_data(wt, sta->ptk.kek, sta->ptk.kek_len,
+					   ver, hdr, &decrypted_len);
 	if (decrypted == NULL) {
 		add_note(wt, MSG_INFO, "Failed to decrypt EAPOL-Key Key Data");
 		return;
@@ -854,7 +887,7 @@
 	}
 
 	if (sta->ptk_set &&
-	    check_mic(sta->ptk.kck, sta->key_mgmt,
+	    check_mic(sta->ptk.kck, sta->ptk.kck_len, sta->key_mgmt,
 		      key_info & WPA_KEY_INFO_TYPE_MASK,
 		      data, len) < 0) {
 		add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 2/2 MIC");
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
index 367a6b5..45433dd 100644
--- a/wlantest/rx_mgmt.c
+++ b/wlantest/rx_mgmt.c
@@ -1,6 +1,6 @@
 /*
  * Received Management frame processing
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, 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,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "common/defs.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "crypto/aes_wrap.h"
@@ -52,16 +53,19 @@
 	const struct ieee80211_mgmt *mgmt;
 	struct wlantest_bss *bss;
 	struct ieee802_11_elems elems;
+	size_t offset;
 
 	mgmt = (const struct ieee80211_mgmt *) data;
+	offset = mgmt->u.beacon.variable - data;
+	if (len < offset)
+		return;
 	bss = bss_get(wt, mgmt->bssid);
 	if (bss == NULL)
 		return;
 	if (bss->proberesp_seen)
 		return; /* do not override with Beacon data */
 	bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
-	if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
-				   len - (mgmt->u.beacon.variable - data),
+	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - offset,
 				   &elems, 0) == ParseFailed) {
 		if (bss->parse_error_reported)
 			return;
@@ -80,16 +84,19 @@
 	const struct ieee80211_mgmt *mgmt;
 	struct wlantest_bss *bss;
 	struct ieee802_11_elems elems;
+	size_t offset;
 
 	mgmt = (const struct ieee80211_mgmt *) data;
+	offset = mgmt->u.probe_resp.variable - data;
+	if (len < offset)
+		return;
 	bss = bss_get(wt, mgmt->bssid);
 	if (bss == NULL)
 		return;
 
 	bss->counters[WLANTEST_BSS_COUNTER_PROBE_RESPONSE]++;
 	bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
-	if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
-				   len - (mgmt->u.probe_resp.variable - data),
+	if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - offset,
 				   &elems, 0) == ParseFailed) {
 		if (bss->parse_error_reported)
 			return;
@@ -341,7 +348,6 @@
 				 "AssocResp from " MACSTR,
 				 MAC2STR(mgmt->sa));
 		} else if (elems.timeout_int == NULL ||
-			   elems.timeout_int_len != 5 ||
 			   elems.timeout_int[0] !=
 			   WLAN_TIMEOUT_ASSOC_COMEBACK) {
 			add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
@@ -474,7 +480,6 @@
 				 "ReassocResp from " MACSTR,
 				 MAC2STR(mgmt->sa));
 		} else if (elems.timeout_int == NULL ||
-			   elems.timeout_int_len != 5 ||
 			   elems.timeout_int[0] !=
 			   WLAN_TIMEOUT_ASSOC_COMEBACK) {
 			add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
@@ -753,12 +758,22 @@
 }
 
 
-static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
+static int check_mmie_mic(unsigned int mgmt_group_cipher,
+			  const u8 *igtk, size_t igtk_len,
+			  const u8 *data, size_t len)
 {
 	u8 *buf;
 	u8 mic[16];
 	u16 fc;
 	const struct ieee80211_hdr *hdr;
+	int ret, mic_len;
+
+	if (!mgmt_group_cipher || igtk_len < 16)
+		return -1;
+	mic_len = mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
+
+	if (len < 24 || len - 24 < mic_len)
+		return -1;
 
 	buf = os_malloc(len + 20 - 24);
 	if (buf == NULL)
@@ -772,19 +787,45 @@
 	os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
 
 	/* Frame body with MMIE MIC masked to zero */
-	os_memcpy(buf + 20, data + 24, len - 24 - 8);
-	os_memset(buf + 20 + len - 24 - 8, 0, 8);
+	os_memcpy(buf + 20, data + 24, len - 24 - mic_len);
+	os_memset(buf + 20 + len - 24 - mic_len, 0, mic_len);
 
 	wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
 	/* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
-	if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
+	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+		ret = omac1_aes_128(igtk, buf, len + 20 - 24, mic);
+	} else if (mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256) {
+		ret = omac1_aes_256(igtk, buf, len + 20 - 24, mic);
+	} else if (mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+		 mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256) {
+		u8 nonce[12], *npos;
+		const u8 *ipn;
+
+		ipn = data + len - mic_len - 6;
+
+		/* Nonce: A2 | IPN */
+		os_memcpy(nonce, hdr->addr2, ETH_ALEN);
+		npos = nonce + ETH_ALEN;
+		*npos++ = ipn[5];
+		*npos++ = ipn[4];
+		*npos++ = ipn[3];
+		*npos++ = ipn[2];
+		*npos++ = ipn[1];
+		*npos++ = ipn[0];
+
+		ret = aes_gmac(igtk, igtk_len, nonce, sizeof(nonce),
+			       buf, len + 20 - 24, mic);
+	} else {
+		ret = -1;
+	}
+	if (ret < 0) {
 		os_free(buf);
 		return -1;
 	}
 
 	os_free(buf);
 
-	if (os_memcmp(data + len - 8, mic, 8) != 0)
+	if (os_memcmp(data + len - mic_len, mic, mic_len) != 0)
 		return -1;
 
 	return 0;
@@ -798,6 +839,7 @@
 	const u8 *mmie;
 	u16 keyid;
 	struct wlantest_bss *bss;
+	size_t mic_len;
 
 	mgmt = (const struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
@@ -814,8 +856,11 @@
 	if (bss == NULL)
 		return 0; /* No key known yet */
 
-	if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
-	    data[len - 17] != 16) {
+	mic_len = bss->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
+
+	if (len < 24 + 10 + mic_len ||
+	    data[len - (10 + mic_len)] != WLAN_EID_MMIE ||
+	    data[len - (10 + mic_len - 1)] != 8 + mic_len) {
 		/* No MMIE */
 		if (bss->rsn_capab & WPA_CAPABILITY_MFPC) {
 			add_note(wt, MSG_INFO, "Robust group-addressed "
@@ -827,7 +872,7 @@
 		return 0;
 	}
 
-	mmie = data + len - 16;
+	mmie = data + len - (8 + mic_len);
 	keyid = WPA_GET_LE16(mmie);
 	if (keyid & 0xf000) {
 		add_note(wt, MSG_INFO, "MMIE KeyID reserved bits not zero "
@@ -842,9 +887,9 @@
 	}
 	wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
 	wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
-	wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
+	wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, mic_len);
 
-	if (!bss->igtk_set[keyid]) {
+	if (!bss->igtk_len[keyid]) {
 		add_note(wt, MSG_DEBUG, "No IGTK known to validate BIP frame");
 		return 0;
 	}
@@ -856,7 +901,8 @@
 		wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
 	}
 
-	if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
+	if (check_mmie_mic(bss->mgmt_group_cipher, bss->igtk[keyid],
+			   bss->igtk_len[keyid], data, len) < 0) {
 		add_note(wt, MSG_INFO, "Invalid MMIE MIC in a frame from "
 			 MACSTR, MAC2STR(mgmt->sa));
 		bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
@@ -941,7 +987,7 @@
 		wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
 	}
 
-	decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data + 24, len - 24, dlen);
+	decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data + 24, len - 24, dlen);
 	if (decrypted) {
 		os_memcpy(rsc, pn, 6);
 		frame = os_malloc(24 + *dlen);
diff --git a/wlantest/rx_tdls.c b/wlantest/rx_tdls.c
index d9247c1..0c012a9 100644
--- a/wlantest/rx_tdls.c
+++ b/wlantest/rx_tdls.c
@@ -142,11 +142,12 @@
 	struct rsn_ftie *tmp_ftie;
 
 	if (elems->link_id == NULL || elems->rsn_ie == NULL ||
-	    elems->timeout_int == NULL || elems->ftie == NULL)
+	    elems->timeout_int == NULL || elems->ftie == NULL ||
+	    elems->ftie_len < sizeof(struct rsn_ftie))
 		return -1;
 
 	len = 2 * ETH_ALEN + 1 + 2 + 18 + 2 + elems->rsn_ie_len +
-		2 + elems->timeout_int_len + 2 + elems->ftie_len;
+		2 + 5 + 2 + elems->ftie_len;
 
 	buf = os_zalloc(len);
 	if (buf == NULL)
@@ -168,8 +169,8 @@
 	os_memcpy(pos, elems->rsn_ie - 2, 2 + elems->rsn_ie_len);
 	pos += 2 + elems->rsn_ie_len;
 	/* 6) Timeout Interval IE */
-	os_memcpy(pos, elems->timeout_int - 2, 2 + elems->timeout_int_len);
-	pos += 2 + elems->timeout_int_len;
+	os_memcpy(pos, elems->timeout_int - 2, 2 + 5);
+	pos += 2 + 5;
 	/* 7) FTIE, with the MIC field of the FTIE set to 0 */
 	os_memcpy(pos, elems->ftie - 2, 2 + elems->ftie_len);
 	pos += 2;
@@ -488,7 +489,8 @@
 	const struct rsn_ftie *rx_ftie;
 	struct rsn_ftie *tmp_ftie;
 
-	if (elems->link_id == NULL || elems->ftie == NULL)
+	if (elems->link_id == NULL || elems->ftie == NULL ||
+	    elems->ftie_len < sizeof(struct rsn_ftie))
 		return -1;
 
 	len = 2 + 18 + 2 + 1 + 1 + 2 + elems->ftie_len;
diff --git a/wlantest/sta.c b/wlantest/sta.c
index 0cd5bd3..1268b8a 100644
--- a/wlantest/sta.c
+++ b/wlantest/sta.c
@@ -1,6 +1,6 @@
 /*
  * STA list
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -170,7 +170,7 @@
 	wpa_printf(MSG_INFO, "STA " MACSTR
 		   " proto=%s%s%s%s"
 		   "pairwise=%s%s%s%s%s%s%s"
-		   "key_mgmt=%s%s%s%s%s%s%s%s%s%s"
+		   "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s"
 		   "rsn_capab=%s%s%s%s%s",
 		   MAC2STR(sta->addr),
 		   sta->proto == 0 ? "OPEN " : "",
@@ -199,6 +199,8 @@
 		   sta->key_mgmt & WPA_KEY_MGMT_OSEN ? "OSEN " : "",
 		   sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B ?
 		   "EAP-SUITE-B " : "",
+		   sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ?
+		   "EAP-SUITE-B-192 " : "",
 		   sta->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
 		   sta->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
 		   "NO_PAIRWISE " : "",
diff --git a/wlantest/test_vectors.c b/wlantest/test_vectors.c
index 0800db7..321d930 100644
--- a/wlantest/test_vectors.c
+++ b/wlantest/test_vectors.c
@@ -159,7 +159,8 @@
 	wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn));
 	wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame));
 
-	prot = bip_protect(igtk, frame, sizeof(frame), ipn, 4, &prot_len);
+	prot = bip_protect(igtk, sizeof(igtk), frame, sizeof(frame),
+			   ipn, 4, &prot_len);
 	if (prot == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to protect BIP frame");
 		return;
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
index a214141..ab3b2fc 100644
--- a/wlantest/wlantest.c
+++ b/wlantest/wlantest.c
@@ -1,6 +1,6 @@
 /*
  * wlantest - IEEE 802.11 protocol monitoring and testing tool
- * Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -210,10 +210,16 @@
 		if (p == NULL)
 			break;
 		if (ptk_len < 48) {
-			os_memcpy(p->ptk.tk1, ptk, ptk_len);
+			os_memcpy(p->ptk.tk, ptk, ptk_len);
+			p->ptk.tk_len = ptk_len;
 			p->ptk_len = 32 + ptk_len;
 		} else {
-			os_memcpy(&p->ptk, ptk, ptk_len);
+			os_memcpy(p->ptk.kck, ptk, 16);
+			p->ptk.kck_len = 16;
+			os_memcpy(p->ptk.kek, ptk + 16, 16);
+			p->ptk.kek_len = 16;
+			os_memcpy(p->ptk.tk, ptk + 32, ptk_len - 32);
+			p->ptk.tk_len = ptk_len - 32;
 			p->ptk_len = ptk_len;
 		}
 		dl_list_add(&wt->ptk, &p->list);
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index 5747149..1d8088f 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -145,8 +145,8 @@
 	size_t gtk_len[4];
 	int gtk_idx;
 	u8 rsc[4][6];
-	u8 igtk[6][16];
-	int igtk_set[6];
+	u8 igtk[6][32];
+	size_t igtk_len[6];
 	int igtk_idx;
 	u8 ipn[6][6];
 	u32 counters[NUM_WLANTEST_BSS_COUNTER];
@@ -284,8 +284,8 @@
 u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr,
 		 const u8 *data, size_t data_len, size_t *decrypted_len);
 
-u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid,
-		 size_t *prot_len);
+u8 * bip_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
+		 u8 *ipn, int keyid, size_t *prot_len);
 u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
 		      u8 *ipn, int keyid, size_t *prot_len);
 
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 7d7f1b6..657784b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -40,6 +40,9 @@
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
 L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\"
 
+# Use Android specific directory for wpa_cli command completion history
+L_CFLAGS += -DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/misc/wifi\"
+
 # To force sizeof(enum) = 4
 ifeq ($(TARGET_ARCH),arm)
 L_CFLAGS += -mabi=aapcs-linux
@@ -189,6 +192,11 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
 ifdef CONFIG_IEEE80211W
 L_CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -266,6 +274,7 @@
 
 ifdef CONFIG_P2P
 OBJS += p2p_supplicant.c
+OBJS += p2p_supplicant_sd.c
 OBJS += src/p2p/p2p.c
 OBJS += src/p2p/p2p_utils.c
 OBJS += src/p2p/p2p_parse.c
@@ -369,7 +378,7 @@
 ifdef CONFIG_EAP_UNAUTH_TLS
 # EAP-UNAUTH-TLS
 L_CFLAGS += -DEAP_UNAUTH_TLS
-ifndef CONFIG_EAP_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
 OBJS += src/eap_peer/eap_tls.c
 OBJS_h += src/eap_server/eap_server_tls.c
 TLS_FUNCS=y
@@ -990,38 +999,6 @@
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
 
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_schannel.c
-endif
-OBJS += src/crypto/crypto_cryptoapi.c
-OBJS_p += src/crypto/crypto_cryptoapi.c
-ifdef NEED_FIPS186_2_PRF
-OBJS += src/crypto/fips_prf_internal.c
-OBJS += src/crypto/sha1-internal.c
-endif
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_nss.c
-LIBS += -lssl3
-endif
-OBJS += src/crypto/crypto_nss.c
-OBJS_p += src/crypto/crypto_nss.c
-ifdef NEED_FIPS186_2_PRF
-OBJS += src/crypto/fips_prf_internal.c
-OBJS += src/crypto/sha1-internal.c
-endif
-LIBS += -lnss3
-LIBS_p += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
 CONFIG_CRYPTO=internal
@@ -1139,7 +1116,9 @@
 AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += src/crypto/aes-unwrap.c
+endif
 ifdef NEED_AES_EAX
 AESOBJS += src/crypto/aes-eax.c
 NEED_AES_CTR=y
@@ -1160,12 +1139,16 @@
 endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += src/crypto/aes-wrap.c
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += src/crypto/aes-cbc.c
 endif
+endif
 ifdef NEED_AES_ENC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += src/crypto/aes-internal-enc.c
@@ -1207,8 +1190,10 @@
 
 MD5OBJS =
 ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
 MD5OBJS += src/crypto/md5.c
 endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += src/crypto/md5-internal.c
@@ -1254,6 +1239,9 @@
 endif
 OBJS += $(SHA256OBJS)
 endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+endif
 
 ifdef NEED_DH_GROUPS
 OBJS += src/crypto/dh_groups.c
@@ -1401,6 +1389,7 @@
 endif
 
 OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/hw_features_common.c
 
 ifdef NEED_EAP_COMMON
 OBJS += src/eap_common/eap_common.c
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index f09e7a0..1ac79b4 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,83 @@
 ChangeLog for wpa_supplicant
 
+2015-03-15 - v2.4
+	* allow OpenSSL cipher configuration to be set for internal EAP server
+	  (openssl_ciphers parameter)
+	* fixed number of small issues based on hwsim test case failures and
+	  static analyzer reports
+	* P2P:
+	  - add new=<0/1> flag to P2P-DEVICE-FOUND events
+	  - add passive channels in invitation response from P2P Client
+	  - enable nl80211 P2P_DEVICE support by default
+	  - fix regresssion in disallow_freq preventing search on social
+	    channels
+	  - fix regressions in P2P SD query processing
+	  - try to re-invite with social operating channel if no common channels
+	    in invitation
+	  - allow cross connection on parent interface (this fixes number of
+	    use cases with nl80211)
+	  - add support for P2P services (P2PS)
+	  - add p2p_go_ctwindow configuration parameter to allow GO CTWindow to
+	    be configured
+	* increase postponing of EAPOL-Start by one second with AP/GO that
+	  supports WPS 2.0 (this makes it less likely to trigger extra roundtrip
+	  of identity frames)
+	* add support for PMKSA caching with SAE
+	* add support for control mesh BSS (IEEE 802.11s) operations
+	* fixed number of issues with D-Bus P2P commands
+	* fixed regression in ap_scan=2 special case for WPS
+	* fixed macsec_validate configuration
+	* add a workaround for incorrectly behaving APs that try to use
+	  EAPOL-Key descriptor version 3 when the station supports PMF even if
+	  PMF is not enabled on the AP
+	* allow TLS v1.1 and v1.2 to be negotiated by default; previous behavior
+	  of disabling these can be configured to work around issues with broken
+	  servers with phase1="tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1"
+	* add support for Suite B (128-bit and 192-bit level) key management and
+	  cipher suites
+	* add WMM-AC support (WMM_AC_ADDTS/WMM_AC_DELTS)
+	* improved BSS Transition Management processing
+	* add support for neighbor report
+	* add support for link measurement
+	* fixed expiration of BSS entry with all-zeros BSSID
+	* add optional LAST_ID=x argument to LIST_NETWORK to allow all
+	  configured networks to be listed even with huge number of network
+	  profiles
+	* add support for EAP Re-Authentication Protocol (ERP)
+	* fixed EAP-IKEv2 fragmentation reassembly
+	* improved PKCS#11 configuration for OpenSSL
+	* set stdout to be line-buffered
+	* add TDLS channel switch configuration
+	* add support for MAC address randomization in scans with nl80211
+	* enable HT for IBSS if supported by the driver
+	* add BSSID black and white lists (bssid_blacklist, bssid_whitelist)
+	* add support for domain_suffix_match with GnuTLS
+	* add OCSP stapling client support with GnuTLS
+	* include peer certificate in EAP events even without a separate probe
+	  operation; old behavior can be restored with cert_in_cb=0
+	* add peer ceritficate alt subject name to EAP events
+	  (CTRL-EVENT-EAP-PEER-ALT)
+	* add domain_match network profile parameter (similar to
+	  domain_suffix_match, but full match is required)
+	* enable AP/GO mode HT Tx STBC automatically based on driver support
+	* add ANQP-QUERY-DONE event to provide information on ANQP parsing
+	  status
+	* allow passive scanning to be forced with passive_scan=1
+	* add a workaround for Linux packet socket behavior when interface is in
+	  bridge
+	* increase 5 GHz band preference in BSS selection (estimate SNR, if info
+	  not available from driver; estimate maximum throughput based on common
+	  HT/VHT/specific TX rate support)
+	* add INTERWORKING_ADD_NETWORK ctrl_iface command; this can be used to
+	  implement Interworking network selection behavior in upper layers
+	  software components
+	* add optional reassoc_same_bss_optim=1 (disabled by default)
+	  optimization to avoid unnecessary Authentication frame exchange
+	* extend TDLS frame padding workaround to cover all packets
+	* allow wpa_supplicant to recover nl80211 functionality if the cfg80211
+	  module gets removed and reloaded without restarting wpa_supplicant
+	* allow hostapd DFS implementation to be used in wpa_supplicant AP mode
+
 2014-10-09 - v2.3
 	* fixed number of minor issues identified in static analyzer warnings
 	* fixed wfd_dev_info to be more careful and not read beyond the buffer
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 06ba18f..af2d924 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -10,6 +10,7 @@
 export BINDIR ?= /usr/local/sbin/
 PKG_CONFIG ?= pkg-config
 
+CFLAGS += $(EXTRA_CFLAGS)
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
@@ -104,6 +105,7 @@
 OBJS_p += ../src/utils/trace.o
 OBJS_c += ../src/utils/trace.o
 OBJS_priv += ../src/utils/trace.o
+LIBCTRL += ../src/utils/trace.o
 LDFLAGS += -rdynamic
 CFLAGS += -funwind-tables
 ifdef CONFIG_WPA_TRACE_BFD
@@ -192,6 +194,11 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
 ifdef CONFIG_IEEE80211W
 CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -269,6 +276,7 @@
 
 ifdef CONFIG_P2P
 OBJS += p2p_supplicant.o
+OBJS += p2p_supplicant_sd.o
 OBJS += ../src/p2p/p2p.o
 OBJS += ../src/p2p/p2p_utils.o
 OBJS += ../src/p2p/p2p_parse.o
@@ -309,6 +317,10 @@
 NEED_GAS=y
 endif
 
+ifdef CONFIG_NO_ROAMING
+CFLAGS += -DCONFIG_NO_ROAMING
+endif
+
 include ../src/drivers/drivers.mak
 ifdef CONFIG_AP
 OBJS_d += $(DRV_BOTH_OBJS)
@@ -371,7 +383,7 @@
 ifdef CONFIG_EAP_UNAUTH_TLS
 # EAP-UNAUTH-TLS
 CFLAGS += -DEAP_UNAUTH_TLS
-ifndef CONFIG_EAP_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
 OBJS += ../src/eap_peer/eap_tls.o
 OBJS_h += ../src/eap_server/eap_server_tls.o
 TLS_FUNCS=y
@@ -1005,38 +1017,6 @@
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
 
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_schannel.o
-endif
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.o
-endif
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-OBJS_p += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.o
-endif
-LIBS += -lnss3
-LIBS_p += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
 CONFIG_CRYPTO=internal
@@ -1154,7 +1134,9 @@
 AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
 endif
 
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += ../src/crypto/aes-unwrap.o
+endif
 ifdef NEED_AES_EAX
 AESOBJS += ../src/crypto/aes-eax.o
 NEED_AES_CTR=y
@@ -1178,12 +1160,16 @@
 endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += ../src/crypto/aes-wrap.o
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
+endif
 ifdef NEED_AES_ENC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-enc.o
@@ -1220,8 +1206,10 @@
 endif
 
 ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
 MD5OBJS += ../src/crypto/md5.o
 endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += ../src/crypto/md5-internal.o
@@ -1267,6 +1255,9 @@
 endif
 OBJS += $(SHA256OBJS)
 endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
+endif
 
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
@@ -1421,6 +1412,7 @@
 endif
 
 OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/hw_features_common.o
 
 ifdef NEED_EAP_COMMON
 OBJS += ../src/eap_common/eap_common.o
@@ -1523,6 +1515,7 @@
 OBJS += wpas_module_tests.o
 OBJS += ../src/utils/utils_module_tests.o
 OBJS += ../src/common/common_module_tests.o
+OBJS += ../src/crypto/crypto_module_tests.o
 ifdef CONFIG_WPS
 OBJS += ../src/wps/wps_module_tests.o
 endif
@@ -1636,6 +1629,15 @@
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
 	@$(E) "  LD " $@
 
+LIBCTRL += ../src/common/wpa_ctrl.o
+LIBCTRL += ../src/utils/os_$(CONFIG_OS).o
+LIBCTRL += ../src/utils/wpa_debug.o
+
+libwpa_ctrl.a: $(LIBCTRL)
+	$(Q)rm -f $@
+	$(Q)$(AR) crs $@ $?
+	@$(E) "  AR " $@
+
 link_test: $(OBJS) $(OBJS_h) tests/link_test.o
 	$(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
 	@$(E) "  LD " $@
@@ -1755,5 +1757,6 @@
 	rm -f nfc_pw_token
 	rm -f lcov.info
 	rm -rf lcov-html
+	rm -f libwpa_ctrl.a
 
 -include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 653848e..f9c65d2 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 58c2475..161dc06 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -172,7 +172,7 @@
 #	If set, this FQDN is used as a suffix match requirement for the AAA
 #	server certificate in SubjectAltName dNSName element(s). If a
 #	matching dNSName is found, this constraint is met. If no dNSName
-#	values are present, this constraint is matched against SubjetName CN
+#	values are present, this constraint is matched against SubjectName CN
 #	using same suffix match comparison. Suffix match here means that the
 #	host/domain name is compared one label at a time starting from the
 #	top-level domain and all the labels in @domain_suffix_match shall be
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 5c1e4f9..6a5b032 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -73,7 +73,7 @@
 
 p2p_find [timeout in seconds] [type=<social|progressive>] \
 	[dev_id=<addr>] [dev_type=<device type>] \
-	[delay=<search delay in ms>]
+	[delay=<search delay in ms>] [seek=<service name>] [freq=<MHz>]
 
 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,7 +81,9 @@
 like the default behavior, but it will scan through all the channels
 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.
+full scan. When the type parameter is not included (i.e., full scan), the
+optional freq parameter can be used to override the first scan to use only
+the specified channel after which only social channels are scanned.
 
 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
@@ -92,6 +94,24 @@
 (primary or secondary) to search for, e.g.,
 "p2p_find dev_type=1-0050F204-1".
 
+
+With one or more seek arguments, the command sends Probe Request frames
+for a P2PS service. For example,
+p2p_find 5 dev_id=11:22:33:44:55:66 seek=alt.example.chat seek=alt.example.video
+
+Parameters description:
+    Timeout - Optional ASCII base-10-encoded u16. If missing, request will not
+	time out and must be canceled manually
+    dev_id - Optional to request responses from a single known remote device
+    Service Name - Mandatory UTF-8 string for ASP seeks
+	Service name must match the remote service being advertised exactly
+	(no prefix matching).
+	Service name may be empty, in which case all ASP services will be
+	returned, and may be filtered with p2p_serv_disc_req settings, and
+	p2p_serv_asp_resp results.
+	Multiple service names may be requested, but if it exceeds internal
+	limit, it will automatically revert to requesting all ASP services.
+
 p2p_listen [timeout in seconds]
 
 Start Listen-only state (become discoverable without searching for
@@ -128,9 +148,9 @@
 out whether the peer device is operating as a GO and if so, use
 join-a-group style PD instead of GO Negotiation style PD.
 
-p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
+p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
 	[persistent|persistent=<network id>] [join|auth]
-	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc]
+	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
 
 Start P2P group formation with a discovered P2P peer. This includes
 optional group owner negotiation, group interface setup, provisioning,
@@ -171,6 +191,69 @@
 P2P implementations that require this to allow the user to accept the
 connection.
 
+"auto" can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group operation rather than GO Negotiation.
+
+P2PS attribute changes to p2p_connect command:
+
+P2PS supports two WPS provisioning methods namely PIN method and P2PS default.
+The remaining paramters hold same role as in legacy P2P. In case of P2PS default
+config method "p2ps" keyword is added in p2p_connect command.
+
+For example:
+p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join
+	(WPS Method = P2PS default)
+
+p2p_connect 02:0a:f5:85:11:00 45629034 keypad persistent
+	(WPS Method = PIN)
+
+p2p_asp_provision <peer MAC address> <adv_id=peer adv id>
+	<adv_mac=peer MAC address> [role=2|4|1] <session=session id>
+	<session_mac=initiator mac address>
+	[info='service info'] <method=Default|keypad|Display>
+
+This command starts provision discovery with the P2PS enabled peer device.
+
+For example,
+p2p_asp_provision 00:11:22:33:44:55 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 session=12ab34 session_mac=00:11:22:33:44:55 info='name=john' method=1000
+
+Parameter description:
+    MAC address - Mandatory
+    adv_id - Mandatory remote Advertising ID of service connection is being
+	established for
+    adv_mac - Mandatory MAC address that owns/registered the service
+    role - Optional
+	2 (group client only) or 4 (group owner only)
+	if not present (or 1) role is negotiated by the two peers.
+    session - Mandatory Session ID of the first session to be established
+    session_mac - Mandatory MAC address that owns/initiated the session
+    method - Optional method to request for provisioning (1000 - P2PS Default,
+	100 - Keypad(PIN), 8 - Display(PIN))
+    info - Optional UTF-8 string. Hint for service to indicate possible usage
+	parameters - Escape single quote & backslash:
+	with a backslash 0x27 == ' == \', and 0x5c == \ == \\
+
+p2p_asp_provision_resp <peer mac address> <adv_id= local adv id>
+	<adv_mac=local MAC address> <role=1|2|4> <status=0>
+	<session=session id> <session_mac=peer MAC address>
+
+This command sends a provision discovery response from responder side.
+
+For example,
+p2p_asp_provision_resp 00:55:44:33:22:11 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 status=0 session=12ab34 session_mac=00:11:22:33:44:55
+
+Parameters definition:
+    MAC address - Mandatory
+    adv_id - Mandatory local Advertising ID of service connection is being
+	established for
+    adv_mac - Mandatory MAC address that owns/registered the service
+    role -  Optional 2 (group client only) or 4 (group owner only)
+	if not present (or 1) role is negotiated by the two peers.
+    status - Mandatory Acceptance/Rejection code of Provisioning
+    session - Mandatory Session ID of the first session to be established
+    session_mac - Mandatory MAC address that owns/initiated the session
+
 p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
 	[ht40] [vht]
 
@@ -215,6 +298,70 @@
 
 Service Discovery
 
+p2p_service_add asp <auto accept> <adv id> <status 0/1> <Config Methods>
+	<Service name> [Service Information] [Response Info]
+
+This command can be used to search for a P2PS service which includes
+Play, Send, Display, and Print service. The parameters for this command
+are "asp" to identify the command as P2PS one, auto accept value,
+advertisement id which uniquely identifies the service requests, state
+of the service whether the service is available or not, config methods
+which can be either P2PS method or PIN method, service name followed by
+two optional parameters service information, and response info.
+
+For example,
+p2p_service_add asp 1 4d6fc7 0 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234'
+
+Parameters definition:
+    asp - Mandatory for ASP service registration
+    auto accept - Mandatory ASCII hex-encoded boolean (0 == no auto-accept,
+	1 == auto-accept ANY role, 2 == auto-accept CLIENT role,
+	4 == auto-accept GO role)
+    Advertisement ID - Mandatory non-zero ASCII hex-encoded u32
+	(Must be unique/not yet exist in svc db)
+    State - Mandatory ASCII hex-encoded u8 (0 -- Svc not available,
+	1 -- Svc available, 2-0xff  Application defined)
+    Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config
+	methods)
+    Service Name - Mandatory UTF-8 string
+    Service Information - Optional UTF-8 string
+	Escape single quote & backslash with a backslash:
+	0x27 == ' == \', and 0x5c == \ == \\
+    Session response information -  Optional (used only if auto accept is TRUE)
+	UTF-8 string
+	Escape single quote & backslash with a backslash:
+	0x27 == ' == \', and 0x5c == \ == \\
+
+p2p_service_rep asp <auto accept> <adv id> <status 0/1> <Config Methods>
+	<Service name> [Service Information] [Response Info]
+
+This command can be used to replace the existing service request
+attributes from the initiator side. The replacement is only allowed if
+the advertisement id issued in the command matches with any one entry in
+the list of existing SD queries. If advertisement id doesn't match the
+command returns a failure.
+
+For example,
+p2p_service_rep asp 1 4d6fc7 1 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234'
+
+Parameters definition:
+    asp - Mandatory for ASP service registration
+    auto accept - Mandatory ASCII hex-encoded boolean (1 == true, 0 == false)
+    Advertisement ID - Mandatory non-zero ASCII hex-encoded u32
+	(Must already exist in svc db)
+    State - Mandatory ASCII hex-encoded u8 (can be used to indicate svc
+	available or not available for instance)
+    Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config
+	methods)
+    Service Name - Mandatory UTF-8 string (Must match existing string in svc db)
+    Service Information - Optional UTF-8 string
+	Escape single quote & backslash with a backslash:
+	0x27 == ' == \', and 0x5c == \ == \\
+    Session response information -  Optional (used only if auto accept is TRUE)
+	UTF-8 string
+	Escape single quote & backslash with a backslash:
+	0x27 == ' == \', and 0x5c == \ == \\
+
 p2p_serv_disc_req
 
 Schedule a P2P service discovery request. The parameters for this
@@ -296,6 +443,27 @@
 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_req <Unicast|Broadcast mac address> asp <Transaction ID>
+	<Service Name> [Service Information]
+
+The command can be used for service discovery for P2PS enabled devices.
+
+For example: p2p_serv_disc_req 00:00:00:00:00:00 asp a1 alt.example 'john'
+
+Parameters definition:
+    MAC address - Mandatory Existing
+    asp - Mandatory for ASP queries
+    Transaction ID - Mandatory non-zero ASCII hex-encoded u8 for GAS
+    Service Name Prefix - Mandatory UTF-8 string.
+	Will match from beginning of remote Service Name
+    Service Information Substring - Optional UTF-8 string
+	If Service Information Substring is not included, all services matching
+	Service Name Prefix will be returned.
+	If Service Information Substring is included, both the Substring and the
+	Service Name Prefix must match for service to be returned.
+	If remote service has no Service Information, all Substring searches
+	will fail.
+
 p2p_serv_disc_cancel_req <query identifier>
 
 Cancel a pending P2P service discovery request. This command takes a
@@ -371,6 +539,11 @@
 
 Remove a local UPnP service from internal SD query processing.
 
+p2p_service_del asp <adv id>
+
+Removes the local asp service from internal SD query list.
+For example: p2p_service_del asp 4d6fc7
+
 p2p_service_flush
 
 Remove all local services from internal SD query processing.
@@ -605,6 +778,63 @@
 Remove a network entry from configuration. 
 
 
+P2PS Events/Responses:
+
+P2PS-PROV-START: This events gets triggered when provisioning is issued for
+either seeker or advertiser.
+
+For example,
+P2PS-PROV-START 00:55:44:33:22:11 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 info='xxxx'
+
+Parameters definition:
+    MAC address - always
+    adv_id - always ASCII hex-encoded u32
+    adv_mac - always MAC address that owns/registered the service
+    conncap - always mask of 0x01 (new), 0x02 (group client), 0x04 (group owner)
+	bits
+    session - always Session ID of the first session to be established
+    session_mac - always MAC address that owns/initiated the session
+    info - if available, UTF-8 string
+	Escaped single quote & backslash with a backslash:
+	\' == 0x27 == ', and \\ == 0x5c == \
+
+P2PS-PROV-DONE: When provisioning is completed then this event gets triggered.
+
+For example,
+P2PS-PROV-DONE 00:11:22:33:44:55 status=0 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 [dev_passwd_id=8 | go=p2p-wlan0-0 | join=11:22:33:44:55:66 | persist=0]
+
+Parameters definition:
+    MAC address - always main device address of peer. May be different from MAC
+	ultimately connected to.
+    status - always ascii hex-encoded u8 (0 == success, 12 == deferred success)
+    adv_id - always ascii hex-encoded u32
+    adv_mac - always MAC address that owns/registered the service
+    conncap - always One of: 1 (new), 2 (group client), 4 (group owner) bits
+    session - always Session ID of the first session to be established
+    session_mac - always MAC address that owns/initiated the session
+    dev_passwd_id - only if conncap value == 1 (New GO negotiation)
+	8 - "p2ps" password must be passed in p2p_connect command
+	1 - "display" password must be passed in p2p_connect command
+	5 - "keypad" password must be passed in p2p_connect command
+    join only - if conncap value == 2 (Client Only). Display password and "join"
+	must be passed in p2p_connect and address must be the MAC specified
+    go only - if conncap value == 4 (GO Only). Interface name must be set with a
+	password
+    persist - only if previous persistent group existed between peers and shall
+	be re-used. Group is restarted by sending "p2p_group_add persistent=0"
+	where value is taken from P2P-PROV-DONE
+
+Extended Events/Response
+
+P2P-DEVICE-FOUND 00:11:22:33:44:55 p2p_dev_addr=00:11:22:33:44:55 pri_dev_type=0-00000000-0 name='' config_methods=0x108 dev_capab=0x21 group_capab=0x0 adv_id=111 asp_svc=alt.example.chat
+
+Parameters definition:
+    adv_id - if ASP ASCII hex-encoded u32. If it is reporting the
+	"wildcard service", this value will be 0
+    asp_svc - if ASP this is the service string. If it is reporting the
+	"wildcard service", this value will be org.wi-fi.wfds
+
+
 wpa_cli action script
 ---------------------
 
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 2ebc7f6..bfb69fc 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -26,6 +26,7 @@
 #include "ap/ieee802_1x.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
+#include "ap/dfs.h"
 #include "wps/wps.h"
 #include "common/ieee802_11_defs.h"
 #include "config_ssid.h"
@@ -132,6 +133,7 @@
 				 HT_CAP_INFO_SHORT_GI20MHZ |
 				 HT_CAP_INFO_SHORT_GI40MHZ |
 				 HT_CAP_INFO_RX_STBC_MASK |
+				 HT_CAP_INFO_TX_STBC |
 				 HT_CAP_INFO_MAX_AMSDU_SIZE);
 
 			if (mode->vht_capab && ssid->vht) {
@@ -164,6 +166,13 @@
 
 	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
 
+	if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
+		conf->ieee80211h = 1;
+		conf->ieee80211d = 1;
+		conf->country[0] = wpa_s->conf->country[0];
+		conf->country[1] = wpa_s->conf->country[1];
+	}
+
 #ifdef CONFIG_P2P
 	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
 	    (ssid->mode == WPAS_MODE_P2P_GO ||
@@ -264,6 +273,17 @@
 	else if (wpa_s->conf->beacon_int)
 		conf->beacon_int = wpa_s->conf->beacon_int;
 
+#ifdef CONFIG_P2P
+	if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
+		wpa_printf(MSG_INFO,
+			   "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
+			   wpa_s->conf->p2p_go_ctwindow, conf->beacon_int);
+		conf->p2p_go_ctwindow = 0;
+	} else {
+		conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+	}
+#endif /* CONFIG_P2P */
+
 	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
 		bss->rsn_pairwise = bss->wpa_pairwise;
 	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
@@ -554,6 +574,9 @@
 	else
 		params.uapsd = -1;
 
+	if (ieee80211_is_dfs(params.freq.freq))
+		params.freq.freq = 0; /* set channel after CAC */
+
 	if (wpa_drv_associate(wpa_s, &params) < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
 		return -1;
@@ -684,6 +707,9 @@
 	hostapd_interface_free(wpa_s->ap_iface);
 	wpa_s->ap_iface = NULL;
 	wpa_drv_deinit_ap(wpa_s);
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+		" reason=%d locally_generated=1",
+		MAC2STR(wpa_s->own_addr), WLAN_REASON_DEAUTH_LEAVING);
 }
 
 
@@ -1130,6 +1156,7 @@
 }
 
 
+#ifdef CONFIG_CTRL_IFACE
 int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
 {
 	struct csa_settings settings;
@@ -1140,6 +1167,7 @@
 
 	return ap_switch_channel(wpa_s, &settings);
 }
+#endif /* CONFIG_CTRL_IFACE */
 
 
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
@@ -1237,3 +1265,79 @@
 					      pw ? wpabuf_len(pw) : 0, 1);
 }
 #endif /* CONFIG_WPS_NFC */
+
+
+#ifdef CONFIG_CTRL_IFACE
+int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_data *hapd;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+	hapd = wpa_s->ap_iface->bss[0];
+	return hostapd_ctrl_iface_stop_ap(hapd);
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#ifdef NEED_AP_MLME
+void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+				   struct dfs_event *radar)
+{
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return;
+	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
+	hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq,
+				   radar->ht_enabled, radar->chan_offset,
+				   radar->chan_width,
+				   radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+				struct dfs_event *radar)
+{
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return;
+	wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq);
+	hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq,
+			      radar->ht_enabled, radar->chan_offset,
+			      radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+				 struct dfs_event *radar)
+{
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return;
+	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq,
+				 radar->ht_enabled, radar->chan_offset,
+				 radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+				struct dfs_event *radar)
+{
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return;
+	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq,
+				 radar->ht_enabled, radar->chan_offset,
+				 radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+				     struct dfs_event *radar)
+{
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return;
+	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
+	hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq,
+				 radar->ht_enabled, radar->chan_offset,
+				 radar->chan_width, radar->cf1, radar->cf2);
+}
+#endif /* NEED_AP_MLME */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 4d80c7a..3f4151d 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -80,4 +80,17 @@
 			       struct wpa_ssid *ssid,
 			       struct hostapd_config *conf);
 
+int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
+
+void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+				   struct dfs_event *radar);
+void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+				struct dfs_event *radar);
+void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+				 struct dfs_event *radar);
+void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+				struct dfs_event *radar);
+void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+				     struct dfs_event *radar);
+
 #endif /* AP_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1798439..46ed5aa 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
 /*
  * BSS table
- * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -85,6 +85,7 @@
 
 #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
 #ifdef CONFIG_INTERWORKING
+	ANQP_DUP(capability_list);
 	ANQP_DUP(venue_name);
 	ANQP_DUP(network_auth_type);
 	ANQP_DUP(roaming_consortium);
@@ -94,6 +95,7 @@
 	ANQP_DUP(domain_name);
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
+	ANQP_DUP(hs20_capability_list);
 	ANQP_DUP(hs20_operator_friendly_name);
 	ANQP_DUP(hs20_wan_metrics);
 	ANQP_DUP(hs20_connection_capability);
@@ -154,6 +156,7 @@
 	}
 
 #ifdef CONFIG_INTERWORKING
+	wpabuf_free(anqp->capability_list);
 	wpabuf_free(anqp->venue_name);
 	wpabuf_free(anqp->network_auth_type);
 	wpabuf_free(anqp->roaming_consortium);
@@ -163,6 +166,7 @@
 	wpabuf_free(anqp->domain_name);
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
+	wpabuf_free(anqp->hs20_capability_list);
 	wpabuf_free(anqp->hs20_operator_friendly_name);
 	wpabuf_free(anqp->hs20_wan_metrics);
 	wpabuf_free(anqp->hs20_connection_capability);
@@ -282,6 +286,8 @@
 	dst->noise = src->noise;
 	dst->level = src->level;
 	dst->tsf = src->tsf;
+	dst->est_throughput = src->est_throughput;
+	dst->snr = src->snr;
 
 	calculate_update_time(fetch_time, src->age, &dst->last_update);
 }
@@ -646,7 +652,7 @@
 			MACSTR, MAC2STR(res->bssid));
 		return;
 	}
-	if (ssid[1] > 32) {
+	if (ssid[1] > SSID_MAX_LEN) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
 			MACSTR, MAC2STR(res->bssid));
 		return;
@@ -673,7 +679,7 @@
 	 * (to save memory) */
 
 	mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
-	if (mesh && mesh[1] <= 32)
+	if (mesh && mesh[1] <= SSID_MAX_LEN)
 		ssid = mesh;
 
 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4a624c5..b215380 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -1,6 +1,6 @@
 /*
  * BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -26,6 +26,7 @@
 	/** Number of BSS entries referring to this ANQP data instance */
 	unsigned int users;
 #ifdef CONFIG_INTERWORKING
+	struct wpabuf *capability_list;
 	struct wpabuf *venue_name;
 	struct wpabuf *network_auth_type;
 	struct wpabuf *roaming_consortium;
@@ -35,6 +36,7 @@
 	struct wpabuf *domain_name;
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
+	struct wpabuf *hs20_capability_list;
 	struct wpabuf *hs20_operator_friendly_name;
 	struct wpabuf *hs20_wan_metrics;
 	struct wpabuf *hs20_connection_capability;
@@ -67,7 +69,7 @@
 	/** HESSID */
 	u8 hessid[ETH_ALEN];
 	/** SSID */
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	/** Length of SSID */
 	size_t ssid_len;
 	/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
@@ -86,6 +88,10 @@
 	u64 tsf;
 	/** Time of the last update (i.e., Beacon or Probe Response RX) */
 	struct os_reltime last_update;
+	/** Estimated throughput in kbps */
+	unsigned int est_throughput;
+	/** Signal-to-noise ratio in dB */
+	int snr;
 	/** ANQP data */
 	struct wpa_bss_anqp *anqp;
 	/** Length of the following IE field in octets (from Probe Response) */
@@ -135,4 +141,10 @@
 	return bss->freq > 45000;
 }
 
+static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
+{
+	if (bss != NULL && new_level < 0)
+		bss->level = new_level;
+}
+
 #endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index f478a04..e1f4883 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -235,6 +235,99 @@
 #endif /* NO_CONFIG_WRITE */
 
 
+static int wpa_config_parse_addr_list(const struct parse_data *data,
+				      int line, const char *value,
+				      u8 **list, size_t *num, char *name,
+				      u8 abort_on_error, u8 masked)
+{
+	const char *pos;
+	u8 *buf, *n, addr[2 * ETH_ALEN];
+	size_t count;
+
+	buf = NULL;
+	count = 0;
+
+	pos = value;
+	while (pos && *pos) {
+		while (*pos == ' ')
+			pos++;
+
+		if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
+			if (abort_on_error || count == 0) {
+				wpa_printf(MSG_ERROR,
+					   "Line %d: Invalid %s address '%s'",
+					   line, name, 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 %s address '%s'",
+				   line, name, pos);
+		} else {
+			n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
+			if (n == NULL) {
+				os_free(buf);
+				return -1;
+			}
+			buf = n;
+			os_memmove(buf + 2 * ETH_ALEN, buf,
+				   count * 2 * ETH_ALEN);
+			os_memcpy(buf, addr, 2 * ETH_ALEN);
+			count++;
+			wpa_printf(MSG_MSGDUMP,
+				   "%s: addr=" MACSTR " mask=" MACSTR,
+				   name, MAC2STR(addr),
+				   MAC2STR(&addr[ETH_ALEN]));
+		}
+
+		pos = os_strchr(pos, ' ');
+	}
+
+	os_free(*list);
+	*list = buf;
+	*num = count;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_addr_list(const struct parse_data *data,
+					 const u8 *list, size_t num, char *name)
+{
+	char *value, *end, *pos;
+	int res;
+	size_t i;
+
+	if (list == NULL || num == 0)
+		return NULL;
+
+	value = os_malloc(2 * 20 * num);
+	if (value == NULL)
+		return NULL;
+	pos = value;
+	end = value + 2 * 20 * num;
+
+	for (i = num; i > 0; i--) {
+		const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
+		const u8 *m = a + ETH_ALEN;
+
+		if (i < num)
+			*pos++ = ' ';
+		res = hwaddr_mask_txt(pos, end - pos, a, m);
+		if (res < 0) {
+			os_free(value);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
 static int wpa_config_parse_bssid(const struct parse_data *data,
 				  struct wpa_ssid *ssid, int line,
 				  const char *value)
@@ -280,6 +373,50 @@
 #endif /* NO_CONFIG_WRITE */
 
 
+static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	return wpa_config_parse_addr_list(data, line, value,
+					  &ssid->bssid_blacklist,
+					  &ssid->num_bssid_blacklist,
+					  "bssid_blacklist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
+					  ssid->num_bssid_blacklist,
+					  "bssid_blacklist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	return wpa_config_parse_addr_list(data, line, value,
+					  &ssid->bssid_whitelist,
+					  &ssid->num_bssid_whitelist,
+					  "bssid_whitelist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
+					  ssid->num_bssid_whitelist,
+					  "bssid_whitelist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
 static int wpa_config_parse_psk(const struct parse_data *data,
 				struct wpa_ssid *ssid, int line,
 				const char *value)
@@ -541,8 +678,14 @@
 		else if (os_strcmp(start, "OSEN") == 0)
 			val |= WPA_KEY_MGMT_OSEN;
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
 		else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
 			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+		else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -719,6 +862,7 @@
 	}
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_SUITEB
 	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
 				  pos == buf ? "" : " ");
@@ -728,6 +872,19 @@
 		}
 		pos += ret;
 	}
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+#endif /* CONFIG_SUITEB192 */
 
 	if (pos == buf) {
 		os_free(buf);
@@ -1139,6 +1296,7 @@
 }
 
 
+#ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_eap(const struct parse_data *data,
 				   struct wpa_ssid *ssid)
 {
@@ -1172,6 +1330,7 @@
 
 	return buf;
 }
+#endif /* NO_CONFIG_WRITE */
 
 
 static int wpa_config_parse_password(const struct parse_data *data,
@@ -1254,6 +1413,7 @@
 }
 
 
+#ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_password(const struct parse_data *data,
 					struct wpa_ssid *ssid)
 {
@@ -1287,6 +1447,7 @@
 
 	return buf;
 }
+#endif /* NO_CONFIG_WRITE */
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -1453,53 +1614,10 @@
 					    struct wpa_ssid *ssid, int line,
 					    const char *value)
 {
-	const char *pos;
-	u8 *buf, *n, addr[ETH_ALEN];
-	size_t count;
-
-	buf = NULL;
-	count = 0;
-
-	pos = value;
-	while (pos && *pos) {
-		while (*pos == ' ')
-			pos++;
-
-		if (hwaddr_aton(pos, addr)) {
-			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_array(buf, count + 1, ETH_ALEN);
-			if (n == NULL) {
-				os_free(buf);
-				return -1;
-			}
-			buf = n;
-			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);
-		}
-
-		pos = os_strchr(pos, ' ');
-	}
-
-	os_free(ssid->p2p_client_list);
-	ssid->p2p_client_list = buf;
-	ssid->num_p2p_clients = count;
-
-	return 0;
+	return wpa_config_parse_addr_list(data, line, value,
+					  &ssid->p2p_client_list,
+					  &ssid->num_p2p_clients,
+					  "p2p_client_list", 0, 0);
 }
 
 
@@ -1507,34 +1625,9 @@
 static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
 					       struct wpa_ssid *ssid)
 {
-	char *value, *end, *pos;
-	int res;
-	size_t i;
-
-	if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
-		return NULL;
-
-	value = os_malloc(20 * ssid->num_p2p_clients);
-	if (value == NULL)
-		return NULL;
-	pos = value;
-	end = value + 20 * ssid->num_p2p_clients;
-
-	for (i = ssid->num_p2p_clients; i > 0; i--) {
-		res = os_snprintf(pos, end - pos, MACSTR " ",
-				  MAC2STR(ssid->p2p_client_list +
-					  (i - 1) * ETH_ALEN));
-		if (os_snprintf_error(end - pos, res)) {
-			os_free(value);
-			return NULL;
-		}
-		pos += res;
-	}
-
-	if (pos > value)
-		pos[-1] = '\0';
-
-	return value;
+	return wpa_config_write_addr_list(data, ssid->p2p_client_list,
+					  ssid->num_p2p_clients,
+					  "p2p_client_list");
 }
 #endif /* NO_CONFIG_WRITE */
 
@@ -1597,32 +1690,6 @@
 
 #ifdef CONFIG_MESH
 
-static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
-					 struct wpa_ssid *ssid, int line,
-					 const char *value)
-{
-	int htval = 0;
-
-	if (os_strcmp(value, "NOHT") == 0)
-		htval = CHAN_NO_HT;
-	else if (os_strcmp(value, "HT20") == 0)
-		htval = CHAN_HT20;
-	else if (os_strcmp(value, "HT40-") == 0)
-		htval = CHAN_HT40MINUS;
-	else if (os_strcmp(value, "HT40+") == 0)
-		htval = CHAN_HT40PLUS;
-	else {
-		wpa_printf(MSG_ERROR,
-			   "Line %d: no ht_mode configured.", line);
-		return -1;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
-	ssid->mesh_ht_mode = htval;
-	return 0;
-}
-
-
 static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
 					     struct wpa_ssid *ssid, int line,
 					     const char *value)
@@ -1648,32 +1715,6 @@
 
 #ifndef NO_CONFIG_WRITE
 
-static char * wpa_config_write_mesh_ht_mode(const struct parse_data *data,
-					    struct wpa_ssid *ssid)
-{
-	char *val;
-
-	switch (ssid->mesh_ht_mode) {
-	default:
-		val = NULL;
-		break;
-	case CHAN_NO_HT:
-		val = "NOHT";
-		break;
-	case CHAN_HT20:
-		val = "HT20";
-		break;
-	case CHAN_HT40MINUS:
-		val = "HT40-";
-		break;
-	case CHAN_HT40PLUS:
-		val = "HT40+";
-		break;
-	}
-	return val ? os_strdup(val) : NULL;
-}
-
-
 static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
 						struct wpa_ssid *ssid)
 {
@@ -1773,10 +1814,13 @@
  * functions.
  */
 static const struct parse_data ssid_fields[] = {
-	{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+	{ STR_RANGE(ssid, 0, SSID_MAX_LEN) },
 	{ INT_RANGE(scan_ssid, 0, 1) },
 	{ FUNC(bssid) },
+	{ FUNC(bssid_blacklist) },
+	{ FUNC(bssid_whitelist) },
 	{ FUNC_KEY(psk) },
+	{ INT(mem_only_psk) },
 	{ FUNC(proto) },
 	{ FUNC(key_mgmt) },
 	{ INT(bg_scan_period) },
@@ -1799,6 +1843,7 @@
 	{ STRe(subject_match) },
 	{ STRe(altsubject_match) },
 	{ STRe(domain_suffix_match) },
+	{ STRe(domain_match) },
 	{ STRe(ca_cert2) },
 	{ STRe(ca_path2) },
 	{ STRe(client_cert2) },
@@ -1808,6 +1853,7 @@
 	{ STRe(subject_match2) },
 	{ STRe(altsubject_match2) },
 	{ STRe(domain_suffix_match2) },
+	{ STRe(domain_match2) },
 	{ STRe(phase1) },
 	{ STRe(phase2) },
 	{ STRe(pcsc) },
@@ -1855,8 +1901,8 @@
 	{ INT_RANGE(peerkey, 0, 1) },
 	{ INT_RANGE(mixed_cell, 0, 1) },
 	{ INT_RANGE(frequency, 0, 65000) },
+	{ INT_RANGE(fixed_freq, 0, 1) },
 #ifdef CONFIG_MESH
-	{ FUNC(mesh_ht_mode) },
 	{ FUNC(mesh_basic_rates) },
 	{ INT(dot11MeshMaxRetries) },
 	{ INT(dot11MeshRetryTimeout) },
@@ -2034,6 +2080,7 @@
 	os_free(eap->subject_match);
 	os_free(eap->altsubject_match);
 	os_free(eap->domain_suffix_match);
+	os_free(eap->domain_match);
 	os_free(eap->ca_cert2);
 	os_free(eap->ca_path2);
 	os_free(eap->client_cert2);
@@ -2043,6 +2090,7 @@
 	os_free(eap->subject_match2);
 	os_free(eap->altsubject_match2);
 	os_free(eap->domain_suffix_match2);
+	os_free(eap->domain_match2);
 	os_free(eap->phase1);
 	os_free(eap->phase2);
 	os_free(eap->pcsc);
@@ -2088,6 +2136,8 @@
 	os_free(ssid->freq_list);
 	os_free(ssid->bgscan);
 	os_free(ssid->p2p_client_list);
+	os_free(ssid->bssid_blacklist);
+	os_free(ssid->bssid_whitelist);
 #ifdef CONFIG_HT_OVERRIDES
 	os_free(ssid->ht_mcs);
 #endif /* CONFIG_HT_OVERRIDES */
@@ -2161,6 +2211,7 @@
 {
 	struct wpa_ssid *ssid, *prev = NULL;
 	struct wpa_cred *cred, *cprev;
+	int i;
 
 	ssid = config->ssid;
 	while (ssid) {
@@ -2179,6 +2230,8 @@
 	wpa_config_flush_blobs(config);
 
 	wpabuf_free(config->wps_vendor_ext_m1);
+	for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
+		wpabuf_free(config->wps_vendor_ext[i]);
 	os_free(config->ctrl_interface);
 	os_free(config->ctrl_interface_group);
 	os_free(config->opensc_engine_path);
@@ -2207,6 +2260,7 @@
 	os_free(config->sae_groups);
 	wpabuf_free(config->ap_vendor_elements);
 	os_free(config->osu_dir);
+	os_free(config->bgscan);
 	os_free(config->wowlan_triggers);
 	os_free(config);
 }
@@ -2344,7 +2398,6 @@
 	ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
 #endif /* IEEE8021X_EAPOL */
 #ifdef CONFIG_MESH
-	ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
 	ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
 	ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
 	ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
@@ -2468,6 +2521,9 @@
  */
 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
 {
+#ifdef NO_CONFIG_WRITE
+	return NULL;
+#else /* NO_CONFIG_WRITE */
 	const struct parse_data *field;
 	char *key, *value;
 	size_t i;
@@ -2513,6 +2569,7 @@
 		os_free(value++);
 	os_free(props);
 	return NULL;
+#endif /* NO_CONFIG_WRITE */
 }
 
 
@@ -2899,7 +2956,7 @@
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		struct excluded_ssid *e;
 
-		if (len > MAX_SSID_LEN) {
+		if (len > SSID_MAX_LEN) {
 			wpa_printf(MSG_ERROR, "Line %d: invalid "
 				   "excluded_ssid length %d", line, (int) len);
 			os_free(val);
@@ -3450,11 +3507,13 @@
 	config->ap_scan = DEFAULT_AP_SCAN;
 	config->user_mpm = DEFAULT_USER_MPM;
 	config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
+	config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
 	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->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
+	config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW;
 	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;
@@ -3468,6 +3527,7 @@
 	config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
 	config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
 	config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
+	config->cert_in_cb = DEFAULT_CERT_IN_CB;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3507,6 +3567,8 @@
 	char *name;
 	int (*parser)(const struct global_parse_data *data,
 		      struct wpa_config *config, int line, const char *value);
+	int (*get)(const char *name, struct wpa_config *config, long offset,
+		   char *buf, size_t buflen, int pretty_print);
 	void *param1, *param2, *param3;
 	unsigned int changed_flag;
 };
@@ -3966,22 +4028,81 @@
 #endif /* CONFIG_CTRL_IFACE */
 
 
+static int wpa_config_get_int(const char *name, struct wpa_config *config,
+			      long offset, char *buf, size_t buflen,
+			      int pretty_print)
+{
+	int *val = (int *) (((u8 *) config) + (long) offset);
+
+	if (pretty_print)
+		return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
+	return os_snprintf(buf, buflen, "%d", *val);
+}
+
+
+static int wpa_config_get_str(const char *name, struct wpa_config *config,
+			      long offset, char *buf, size_t buflen,
+			      int pretty_print)
+{
+	char **val = (char **) (((u8 *) config) + (long) offset);
+	int res;
+
+	if (pretty_print)
+		res = os_snprintf(buf, buflen, "%s=%s\n", name,
+				  *val ? *val : "null");
+	else if (!*val)
+		return -1;
+	else
+		res = os_snprintf(buf, buflen, "%s", *val);
+	if (os_snprintf_error(buflen, res))
+		res = -1;
+
+	return res;
+}
+
+
+#ifdef CONFIG_P2P
+static int wpa_config_get_ipv4(const char *name, struct wpa_config *config,
+			       long offset, char *buf, size_t buflen,
+			       int pretty_print)
+{
+	void *val = ((u8 *) config) + (long) offset;
+	int res;
+	char addr[INET_ADDRSTRLEN];
+
+	if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr)))
+		return -1;
+
+	if (pretty_print)
+		res = os_snprintf(buf, buflen, "%s=%s\n", name, addr);
+	else
+		res = os_snprintf(buf, buflen, "%s", addr);
+
+	if (os_snprintf_error(buflen, res))
+		res = -1;
+
+	return res;
+}
+#endif /* CONFIG_P2P */
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
 /* OFFSET: Get offset of a variable within the wpa_config structure */
 #define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
 
-#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
-#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
-#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
 #define INT(f) _INT(f), NULL, NULL
 #define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
-#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
 #define STR(f) _STR(f), NULL, NULL
 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
-#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
-#define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL
+#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL
+#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4,  \
+	OFFSET(f), NULL, NULL
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
@@ -3999,6 +4120,7 @@
 #ifdef CONFIG_MESH
 	{ INT(user_mpm), 0 },
 	{ INT_RANGE(max_peer_links, 0, 255), 0 },
+	{ INT(mesh_max_inactivity), 0 },
 #endif /* CONFIG_MESH */
 	{ INT(disable_scan_offload), 0 },
 	{ INT(fast_reauth), 0 },
@@ -4019,7 +4141,8 @@
 	{ FUNC_NO_VAR(load_dynamic_eap), 0 },
 #ifdef CONFIG_WPS
 	{ FUNC(uuid), CFG_CHANGED_UUID },
-	{ STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+	{ STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN),
+	  CFG_CHANGED_DEVICE_NAME },
 	{ STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
 	{ STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
 	{ STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
@@ -4050,6 +4173,7 @@
 	{ INT(p2p_go_ht40), 0 },
 	{ INT(p2p_go_vht), 0 },
 	{ INT(p2p_disabled), 0 },
+	{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
 	{ INT(p2p_no_group_iface), 0 },
 	{ INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
 	{ IPV4(ip_addr_go), 0 },
@@ -4099,6 +4223,8 @@
 	{ INT(rand_addr_lifetime), 0 },
 	{ INT(preassoc_mac_addr), 0 },
 	{ INT(key_mgmt_offload), 0},
+	{ INT(passive_scan), 0 },
+	{ INT(reassoc_same_bss_optim), 0 },
 };
 
 #undef FUNC
@@ -4113,6 +4239,50 @@
 #define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
 
 
+int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen)
+{
+	int result = 0;
+	size_t i;
+
+	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+		const struct global_parse_data *field = &global_fields[i];
+		int tmp;
+
+		if (!field->get)
+			continue;
+
+		tmp = field->get(field->name, config, (long) field->param1,
+				 buf, buflen, 1);
+		if (tmp < 0)
+			return -1;
+		buf += tmp;
+		buflen -= tmp;
+		result += tmp;
+	}
+	return result;
+}
+
+
+int wpa_config_get_value(const char *name, struct wpa_config *config,
+			 char *buf, size_t buflen)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+		const struct global_parse_data *field = &global_fields[i];
+
+		if (os_strcmp(name, field->name) != 0)
+			continue;
+		if (!field->get)
+			break;
+		return field->get(name, config, (long) field->param1,
+				  buf, buflen, 0);
+	}
+
+	return -1;
+}
+
+
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 {
 	size_t i;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index b3f7eef..16681fd 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -17,6 +17,7 @@
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 #define DEFAULT_USER_MPM 1
 #define DEFAULT_MAX_PEER_LINKS 99
+#define DEFAULT_MESH_MAX_INACTIVITY 300
 #define DEFAULT_FAST_REAUTH 1
 #define DEFAULT_P2P_GO_INTENT 7
 #define DEFAULT_P2P_INTRA_BSS 1
@@ -31,9 +32,12 @@
 #define DEFAULT_P2P_SEARCH_DELAY 500
 #define DEFAULT_RAND_ADDR_LIFETIME 60
 #define DEFAULT_KEY_MGMT_OFFLOAD 1
+#define DEFAULT_CERT_IN_CB 1
+#define DEFAULT_P2P_GO_CTWINDOW 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
+#include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 
 
@@ -166,7 +170,7 @@
 	 * If set, this FQDN is used as a suffix match requirement for the AAA
 	 * server certificate in SubjectAltName dNSName element(s). If a
 	 * matching dNSName is found, this constraint is met. If no dNSName
-	 * values are present, this constraint is matched against SubjetName CN
+	 * values are present, this constraint is matched against SubjectName CN
 	 * using same suffix match comparison. Suffix match here means that the
 	 * host/domain name is compared one label at a time starting from the
 	 * top-level domain and all the labels in @domain_suffix_match shall be
@@ -238,7 +242,7 @@
 	char *phase2;
 
 	struct excluded_ssid {
-		u8 ssid[MAX_SSID_LEN];
+		u8 ssid[SSID_MAX_LEN];
 		size_t ssid_len;
 	} *excluded_ssid;
 	size_t num_excluded_ssid;
@@ -940,6 +944,14 @@
 	int p2p_go_vht;
 
 	/**
+	 * p2p_go_ctwindow - CTWindow to use when operating as GO
+	 *
+	 * By default: 0 (no CTWindow). Values 0-127 can be used to indicate
+	 * the length of the CTWindow in TUs.
+	 */
+	int p2p_go_ctwindow;
+
+	/**
 	 * p2p_disabled - Whether P2P operations are disabled for this interface
 	 */
 	int p2p_disabled;
@@ -1119,6 +1131,39 @@
 	 * Maximum number of mesh peering currently maintained by the STA.
 	 */
 	int max_peer_links;
+
+	/**
+	 * cert_in_cb - Whether to include a peer certificate dump in events
+	 *
+	 * This controls whether peer certificates for authentication server and
+	 * its certificate chain are included in EAP peer certificate events.
+	 */
+	int cert_in_cb;
+
+	/**
+	 * mesh_max_inactivity - Timeout in seconds to detect STA inactivity
+	 *
+	 * This timeout value is used in mesh STA to clean up inactive stations.
+	 * By default: 300 seconds.
+	 */
+	int mesh_max_inactivity;
+
+	/**
+	 * passive_scan - Whether to force passive scan for network connection
+	 *
+	 * This parameter can be used to force only passive scanning to be used
+	 * for network connection cases. It should be noted that this will slow
+	 * down scan operations and reduce likelihood of finding the AP. In
+	 * addition, some use cases will override this due to functional
+	 * requirements, e.g., for finding an AP that uses hidden SSID
+	 * (scan_ssid=1) or P2P device discovery.
+	 */
+	int passive_scan;
+
+	/**
+	 * reassoc_same_bss_optim - Whether to optimize reassoc-to-same-BSS
+	 */
+	int reassoc_same_bss_optim;
 };
 
 
@@ -1137,6 +1182,11 @@
 		   int line);
 int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
 			  const char *value);
+int wpa_config_dump_values(struct wpa_config *config, char *buf,
+			   size_t buflen);
+int wpa_config_get_value(const char *name, struct wpa_config *config,
+			 char *buf, size_t buflen);
+
 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
 char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
 char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5c8b24b..781f5e5 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -11,6 +11,9 @@
  */
 
 #include "includes.h"
+#ifdef ANDROID
+#include <sys/stat.h>
+#endif /* ANDROID */
 
 #include "common.h"
 #include "config.h"
@@ -498,7 +501,12 @@
 
 static void write_psk(FILE *f, struct wpa_ssid *ssid)
 {
-	char *value = wpa_config_get(ssid, "psk");
+	char *value;
+
+	if (ssid->mem_only_psk)
+		return;
+
+	value = wpa_config_get(ssid, "psk");
 	if (value == NULL)
 		return;
 	fprintf(f, "\tpsk=%s\n", value);
@@ -667,7 +675,10 @@
 	STR(ssid);
 	INT(scan_ssid);
 	write_bssid(f, ssid);
+	write_str(f, "bssid_blacklist", ssid);
+	write_str(f, "bssid_whitelist", ssid);
 	write_psk(f, ssid);
+	INT(mem_only_psk);
 	write_proto(f, ssid);
 	write_key_mgmt(f, ssid);
 	INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
@@ -691,6 +702,7 @@
 	STR(subject_match);
 	STR(altsubject_match);
 	STR(domain_suffix_match);
+	STR(domain_match);
 	STR(ca_cert2);
 	STR(ca_path2);
 	STR(client_cert2);
@@ -700,6 +712,7 @@
 	STR(subject_match2);
 	STR(altsubject_match2);
 	STR(domain_suffix_match2);
+	STR(domain_match2);
 	STR(phase1);
 	STR(phase2);
 	STR(pcsc);
@@ -716,6 +729,7 @@
 	INTe(engine);
 	INTe(engine2);
 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+	STR(openssl_ciphers);
 	INTe(erp);
 #endif /* IEEE8021X_EAPOL */
 	for (i = 0; i < 4; i++)
@@ -730,10 +744,13 @@
 	INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
 #endif /* IEEE8021X_EAPOL */
 	INT(mode);
+	INT(no_auto_peer);
 	INT(frequency);
+	INT(fixed_freq);
 	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
 	INT(disabled);
 	INT(peerkey);
+	INT(mixed_cell);
 #ifdef CONFIG_IEEE80211W
 	write_int(f, "ieee80211w", ssid->ieee80211w,
 		  MGMT_FRAME_PROTECTION_DEFAULT);
@@ -744,6 +761,7 @@
 	write_p2p_client_list(f, ssid);
 	write_psk_list(f, ssid);
 #endif /* CONFIG_P2P */
+	INT(ap_max_inactivity);
 	INT(dtim_period);
 	INT(beacon_int);
 #ifdef CONFIG_MACSEC
@@ -754,13 +772,46 @@
 #endif /* CONFIG_HS20 */
 	write_int(f, "mac_addr", ssid->mac_addr, -1);
 #ifdef CONFIG_MESH
-	STR(mesh_ht_mode);
 	STR(mesh_basic_rates);
 	INT_DEF(dot11MeshMaxRetries, DEFAULT_MESH_MAX_RETRIES);
 	INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT);
 	INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT);
 	INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
 #endif /* CONFIG_MESH */
+	INT(wpa_ptk_rekey);
+	INT(ignore_broadcast_ssid);
+#ifdef CONFIG_HT_OVERRIDES
+	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
+	INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
+	INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI);
+	INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC);
+	INT(ht40_intolerant);
+	INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU);
+	INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR);
+	INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY);
+	STR(ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+	INT(disable_vht);
+	INT(vht_capa);
+	INT(vht_capa_mask);
+	INT_DEF(vht_rx_mcs_nss_1, -1);
+	INT_DEF(vht_rx_mcs_nss_2, -1);
+	INT_DEF(vht_rx_mcs_nss_3, -1);
+	INT_DEF(vht_rx_mcs_nss_4, -1);
+	INT_DEF(vht_rx_mcs_nss_5, -1);
+	INT_DEF(vht_rx_mcs_nss_6, -1);
+	INT_DEF(vht_rx_mcs_nss_7, -1);
+	INT_DEF(vht_rx_mcs_nss_8, -1);
+	INT_DEF(vht_tx_mcs_nss_1, -1);
+	INT_DEF(vht_tx_mcs_nss_2, -1);
+	INT_DEF(vht_tx_mcs_nss_3, -1);
+	INT_DEF(vht_tx_mcs_nss_4, -1);
+	INT_DEF(vht_tx_mcs_nss_5, -1);
+	INT_DEF(vht_tx_mcs_nss_6, -1);
+	INT_DEF(vht_tx_mcs_nss_7, -1);
+	INT_DEF(vht_tx_mcs_nss_8, -1);
+#endif /* CONFIG_VHT_OVERRIDES */
 
 #undef STR
 #undef INT
@@ -1070,6 +1121,8 @@
 		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
 	if (config->p2p_go_vht)
 		fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
+	if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
+		fprintf(f, "p2p_go_ctwindow=%u\n", config->p2p_go_ctwindow);
 	if (config->p2p_disabled)
 		fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
 	if (config->p2p_no_group_iface)
@@ -1219,6 +1272,20 @@
 
 	if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS)
 		fprintf(f, "max_peer_links=%d\n", config->max_peer_links);
+
+	if (config->cert_in_cb != DEFAULT_CERT_IN_CB)
+		fprintf(f, "cert_in_cb=%d\n", config->cert_in_cb);
+
+	if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY)
+		fprintf(f, "mesh_max_inactivity=%d\n",
+			config->mesh_max_inactivity);
+
+	if (config->passive_scan)
+		fprintf(f, "passive_scan=%d\n", config->passive_scan);
+
+	if (config->reassoc_same_bss_optim)
+		fprintf(f, "reassoc_same_bss_optim=%d\n",
+			config->reassoc_same_bss_optim);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1234,12 +1301,21 @@
 	struct wpa_config_blob *blob;
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 	int ret = 0;
+	const char *orig_name = name;
+	int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+	char *tmp_name = os_malloc(tmp_len);
+
+	if (tmp_name) {
+		os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
+		name = tmp_name;
+	}
 
 	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
 
 	f = fopen(name, "w");
 	if (f == NULL) {
 		wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
+		os_free(tmp_name);
 		return -1;
 	}
 
@@ -1274,8 +1350,21 @@
 
 	fclose(f);
 
+	if (tmp_name) {
+		int chmod_ret = 0;
+
+#ifdef ANDROID
+		chmod_ret = chmod(tmp_name,
+				  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+#endif /* ANDROID */
+		if (chmod_ret != 0 || rename(tmp_name, orig_name) != 0)
+			ret = -1;
+
+		os_free(tmp_name);
+	}
+
 	wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
-		   name, ret ? "un" : "");
+		   orig_name, ret ? "un" : "");
 	return ret;
 #else /* CONFIG_NO_CONFIG_WRITE */
 	return -1;
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c5cd6e7..dbb5a47 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -13,8 +13,6 @@
 #include "utils/list.h"
 #include "eap_peer/eap_config.h"
 
-#define MAX_SSID_LEN 32
-
 
 #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
 #define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
@@ -27,7 +25,6 @@
 #define DEFAULT_FRAGMENT_SIZE 1398
 
 #define DEFAULT_BG_SCAN_PERIOD -1
-#define DEFAULT_MESH_HT_MODE CHAN_UNDEFINED /* undefined */
 #define DEFAULT_MESH_MAX_RETRIES 2
 #define DEFAULT_MESH_RETRY_TIMEOUT 40
 #define DEFAULT_MESH_CONFIRM_TIMEOUT 40
@@ -133,6 +130,18 @@
 	u8 bssid[ETH_ALEN];
 
 	/**
+	 * bssid_blacklist - List of inacceptable BSSIDs
+	 */
+	u8 *bssid_blacklist;
+	size_t num_bssid_blacklist;
+
+	/**
+	 * bssid_blacklist - List of acceptable BSSIDs
+	 */
+	u8 *bssid_whitelist;
+	size_t num_bssid_whitelist;
+
+	/**
 	 * bssid_set - Whether BSSID is configured for this network
 	 */
 	int bssid_set;
@@ -170,6 +179,14 @@
 	char *ext_psk;
 
 	/**
+	 * mem_only_psk - Whether to keep PSK/passphrase only in memory
+	 *
+	 * 0 = allow psk/passphrase to be stored to the configuration file
+	 * 1 = do not store psk/passphrase to the configuration file
+	 */
+	int mem_only_psk;
+
+	/**
 	 * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
 	 */
 	int pairwise_cipher;
@@ -409,13 +426,9 @@
 	int frequency;
 
 	/**
-	 * mesh_ht_mode - definition of HT mode in mesh mode
-	 *
-	 * Use the given HT mode for mesh networks. The driver will
-	 * adapt to other stations if neccesary, but advertise the
-	 * configured HT mode (HT20/HT40-/HT40+/NOHT).
+	 * fixed_freq - Use fixed frequency for IBSS
 	 */
-	int mesh_ht_mode;
+	int fixed_freq;
 
 	/**
 	 * mesh_basic_rates - BSS Basic rate set for mesh network
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 2917748..a6aafee 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,6 +19,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "crypto/tls.h"
 #include "ap/hostapd.h"
 #include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
@@ -152,7 +153,8 @@
 			}
 			ssid = ns;
 
-			if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+			if ((end - pos) & 0x01 ||
+			    end - pos > 2 * SSID_MAX_LEN ||
 			    hexstr2bin(pos, ssid[ssid_count].ssid,
 				       (end - pos) / 2) < 0) {
 				os_free(ssid);
@@ -208,6 +210,7 @@
 	wpa_s->sme.prev_bssid_set = 0;
 #endif /* CONFIG_SME */
 	wpa_s->reassociate = 1;
+	wpa_s->own_disconnect_req = 1;
 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
@@ -436,6 +439,8 @@
 #endif /* CONFIG_AP */
 	} else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
 		wpa_s->extra_roc_dur = atoi(value);
+	} else if (os_strcasecmp(cmd, "test_failure") == 0) {
+		wpa_s->test_failure = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	} else if (os_strcmp(cmd, "blob") == 0) {
@@ -493,6 +498,10 @@
 				       wpa_s->last_gtk_len);
 		return res;
 #endif /* CONFIG_TESTING_GET_GTK */
+	} else if (os_strcmp(cmd, "tls_library") == 0) {
+		res = tls_get_library_version(buf, buflen);
+	} else {
+		res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
 	}
 
 	if (os_snprintf_error(buflen, res))
@@ -653,6 +662,104 @@
 	return ret;
 }
 
+
+static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 peer[ETH_ALEN];
+	struct hostapd_freq_params freq_params;
+	u8 oper_class;
+	char *pos, *end;
+
+	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Only supported with external setup");
+		return -1;
+	}
+
+	os_memset(&freq_params, 0, sizeof(freq_params));
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	oper_class = strtol(pos, &end, 10);
+	if (pos == end) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Invalid op class provided");
+		return -1;
+	}
+
+	pos = end;
+	freq_params.freq = atoi(pos);
+	if (freq_params.freq == 0) {
+		wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
+		return -1;
+	}
+
+#define SET_FREQ_SETTING(str) \
+	do { \
+		const char *pos2 = os_strstr(pos, " " #str "="); \
+		if (pos2) { \
+			pos2 += sizeof(" " #str "=") - 1; \
+			freq_params.str = atoi(pos2); \
+		} \
+	} while (0)
+
+	SET_FREQ_SETTING(center_freq1);
+	SET_FREQ_SETTING(center_freq2);
+	SET_FREQ_SETTING(bandwidth);
+	SET_FREQ_SETTING(sec_channel_offset);
+#undef SET_FREQ_SETTING
+
+	freq_params.ht_enabled = !!os_strstr(pos, " ht");
+	freq_params.vht_enabled = !!os_strstr(pos, " vht");
+
+	if (hwaddr_aton(cmd, peer)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
+			   cmd);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
+		   " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
+		   MAC2STR(peer), oper_class, freq_params.freq,
+		   freq_params.center_freq1, freq_params.center_freq2,
+		   freq_params.bandwidth, freq_params.sec_channel_offset,
+		   freq_params.ht_enabled ? " HT" : "",
+		   freq_params.vht_enabled ? " VHT" : "");
+
+	return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+					   &freq_params);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 peer[ETH_ALEN];
+
+	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Only supported with external setup");
+		return -1;
+	}
+
+	if (hwaddr_aton(cmd, peer)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
+			   cmd);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
+}
+
 #endif /* CONFIG_TDLS */
 
 
@@ -1598,6 +1705,8 @@
 #ifdef CONFIG_HS20
 	const u8 *hs20;
 #endif /* CONFIG_HS20 */
+	const u8 *sess_id;
+	size_t sess_id_len;
 
 	if (os_strcmp(params, "-DRIVER") == 0)
 		return wpa_drv_status(wpa_s, buf, buflen);
@@ -1620,7 +1729,7 @@
 		if (ssid) {
 			u8 *_ssid = ssid->ssid;
 			size_t ssid_len = ssid->ssid_len;
-			u8 ssid_buf[MAX_SSID_LEN];
+			u8 ssid_buf[SSID_MAX_LEN];
 			if (ssid_len == 0) {
 				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
 				if (_res < 0)
@@ -1830,6 +1939,24 @@
 			pos += res;
 	}
 
+	sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
+	if (sess_id) {
+		char *start = pos;
+
+		ret = os_snprintf(pos, end - pos, "eap_session_id=");
+		if (os_snprintf_error(end - pos, ret))
+			return start - buf;
+		pos += ret;
+		ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
+		if (ret <= 0)
+			return start - buf;
+		pos += ret;
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (os_snprintf_error(end - pos, ret))
+			return start - buf;
+		pos += ret;
+	}
+
 	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
 	if (res >= 0)
 		pos += res;
@@ -2220,6 +2347,7 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_SUITEB
 	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
 		ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
 				  pos == start ? "" : "+");
@@ -2227,6 +2355,25 @@
 			return pos;
 		pos += ret;
 	}
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
+				  pos == start ? "" : "+");
+		if (os_snprintf_error(end - pos, ret))
+			return pos;
+		pos += ret;
+	}
+#endif /* CONFIG_SUITEB192 */
+
+	if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
+		ret = os_snprintf(pos, end - pos, "%sOSEN",
+				  pos == start ? "" : "+");
+		if (os_snprintf_error(end - pos, ret))
+			return pos;
+		pos += ret;
+	}
 
 	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
 
@@ -2295,7 +2442,7 @@
 {
 	char *pos, *end;
 	int ret;
-	const u8 *ie, *ie2, *p2p, *mesh;
+	const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
 
 	mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
 	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2322,8 +2469,12 @@
 		pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
 					    ie2, 2 + ie2[1]);
 	}
+	osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+	if (osen_ie)
+		pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
+					    osen_ie, 2 + osen_ie[1]);
 	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
-	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+	if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
 		ret = os_snprintf(pos, end - pos, "[WEP]");
 		if (os_snprintf_error(end - pos, ret))
 			return -1;
@@ -2698,6 +2849,7 @@
 #endif /* CONFIG_SME */
 			wpa_sm_set_config(wpa_s->wpa, NULL);
 			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+			wpa_s->own_disconnect_req = 1;
 			wpa_supplicant_deauthenticate(
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		}
@@ -2744,6 +2896,7 @@
 		wpa_sm_set_config(wpa_s->wpa, NULL);
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	}
@@ -2795,8 +2948,6 @@
 		wpa_config_update_psk(ssid);
 	else if (os_strcmp(name, "priority") == 0)
 		wpa_config_update_prio_list(wpa_s->conf);
-	else if (os_strcmp(name, "no_auto_peer") == 0)
-		ssid->no_auto_peer = atoi(value);
 
 	return 0;
 }
@@ -2805,7 +2956,7 @@
 static int wpa_supplicant_ctrl_iface_set_network(
 	struct wpa_supplicant *wpa_s, char *cmd)
 {
-	int id, ret, prev_bssid_set;
+	int id, ret, prev_bssid_set, prev_disabled;
 	struct wpa_ssid *ssid;
 	char *name, *value;
 	u8 prev_bssid[ETH_ALEN];
@@ -2835,6 +2986,7 @@
 	}
 
 	prev_bssid_set = ssid->bssid_set;
+	prev_disabled = ssid->disabled;
 	os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
 	ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
 						       value);
@@ -2842,6 +2994,11 @@
 	    (ssid->bssid_set != prev_bssid_set ||
 	     os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
 		wpas_notify_network_bssid_set_changed(wpa_s, ssid);
+
+	if (prev_disabled != ssid->disabled &&
+	    (prev_disabled == 2 || ssid->disabled == 2))
+		wpas_notify_network_type_changed(wpa_s, ssid);
+
 	return ret;
 }
 
@@ -3230,6 +3387,13 @@
 	{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
 };
 
+static const struct cipher_info ciphers_group_mgmt[] = {
+	{ WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
+	{ WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
+	{ WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
+	{ WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
+};
+
 
 static int ctrl_iface_get_capability_pairwise(int res, char *strict,
 					      struct wpa_driver_capa *capa,
@@ -3303,6 +3467,35 @@
 }
 
 
+static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+						struct wpa_driver_capa *capa,
+						char *buf, size_t buflen)
+{
+	int ret;
+	char *pos, *end;
+	unsigned int i;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
+		if (capa->enc & ciphers_group_mgmt[i].capa) {
+			ret = os_snprintf(pos, end - pos, "%s%s",
+					  pos == buf ? "" : " ",
+					  ciphers_group_mgmt[i].name);
+			if (os_snprintf_error(end - pos, ret))
+				return pos - buf;
+			pos += ret;
+		}
+	}
+
+	return pos - buf;
+}
+
+
 static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
 					      struct wpa_driver_capa *capa,
 					      char *buf, size_t buflen)
@@ -3352,6 +3545,23 @@
 		pos += ret;
 	}
 
+#ifdef CONFIG_SUITEB
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_SUITEB192 */
+
 	return pos - buf;
 }
 
@@ -3398,7 +3608,8 @@
 }
 
 
-static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
+					      int res, char *strict,
 					      struct wpa_driver_capa *capa,
 					      char *buf, size_t buflen)
 {
@@ -3442,6 +3653,16 @@
 		pos += ret;
 	}
 
+#ifdef CONFIG_SAE
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+		ret = os_snprintf(pos, end - pos, "%sSAE",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_SAE */
+
 	return pos - buf;
 }
 
@@ -3482,6 +3703,16 @@
 		pos += ret;
 	}
 
+#ifdef CONFIG_MESH
+	if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
+		ret = os_snprintf(pos, end - pos, "%sMESH",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_MESH */
+
 	return pos - buf;
 }
 
@@ -3631,6 +3862,10 @@
 		return ctrl_iface_get_capability_group(res, strict, &capa,
 						       buf, buflen);
 
+	if (os_strcmp(field, "group_mgmt") == 0)
+		return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
+							    buf, buflen);
+
 	if (os_strcmp(field, "key_mgmt") == 0)
 		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
 							  buf, buflen);
@@ -3640,8 +3875,8 @@
 						       buf, buflen);
 
 	if (os_strcmp(field, "auth_alg") == 0)
-		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
-							  buf, buflen);
+		return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
+							  &capa, buf, buflen);
 
 	if (os_strcmp(field, "modes") == 0)
 		return ctrl_iface_get_capability_modes(res, strict, &capa,
@@ -3715,7 +3950,7 @@
 	size_t i;
 	int ret;
 	char *pos, *end;
-	const u8 *ie, *ie2;
+	const u8 *ie, *ie2, *osen_ie;
 
 	pos = buf;
 	end = buf + buflen;
@@ -3832,8 +4067,13 @@
 		if (ie2)
 			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
 						    2 + ie2[1]);
+		osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+		if (osen_ie)
+			pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
+						    osen_ie, 2 + osen_ie[1]);
 		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
-		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+		if (!ie && !ie2 && !osen_ie &&
+		    (bss->caps & IEEE80211_CAP_PRIVACY)) {
 			ret = os_snprintf(pos, end - pos, "[WEP]");
 			if (os_snprintf_error(end - pos, ret))
 				return 0;
@@ -3957,6 +4197,8 @@
 #ifdef CONFIG_INTERWORKING
 	if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
 		struct wpa_bss_anqp *anqp = bss->anqp;
+		pos = anqp_add_hex(pos, end, "anqp_capability_list",
+				   anqp->capability_list);
 		pos = anqp_add_hex(pos, end, "anqp_venue_name",
 				   anqp->venue_name);
 		pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
@@ -3971,6 +4213,8 @@
 		pos = anqp_add_hex(pos, end, "anqp_domain_name",
 				   anqp->domain_name);
 #ifdef CONFIG_HS20
+		pos = anqp_add_hex(pos, end, "hs20_capability_list",
+				   anqp->hs20_capability_list);
 		pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
 				   anqp->hs20_operator_friendly_name);
 		pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
@@ -3995,6 +4239,21 @@
 	}
 #endif /* CONFIG_MESH */
 
+	if (mask & WPA_BSS_MASK_SNR) {
+		ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
+		ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
+				  bss->est_throughput);
+		if (os_snprintf_error(end - pos, ret))
+			return 0;
+		pos += ret;
+	}
+
 	if (mask & WPA_BSS_MASK_DELIM) {
 		ret = os_snprintf(pos, end - pos, "====\n");
 		if (os_snprintf_error(end - pos, ret))
@@ -4270,6 +4529,9 @@
 	u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
 	char *pos;
 	unsigned int search_delay;
+	const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
+	u8 seek_count = 0;
+	int freq = 0;
 
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		wpa_dbg(wpa_s, MSG_INFO,
@@ -4304,8 +4566,181 @@
 	} else
 		search_delay = wpas_p2p_search_delay(wpa_s);
 
+	/* Must be searched for last, because it adds nul termination */
+	pos = os_strstr(cmd, " seek=");
+	while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
+		char *term;
+
+		term = os_strchr(pos + 1, ' ');
+		_seek[seek_count++] = pos + 6;
+		seek = _seek;
+		pos = os_strstr(pos + 6, " seek=");
+
+		if (term)
+			*term = '\0';
+	}
+	if (seek_count > P2P_MAX_QUERY_HASH) {
+		seek[0] = NULL;
+		seek_count = 1;
+	}
+
+	pos = os_strstr(cmd, "freq=");
+	if (pos) {
+		pos += 5;
+		freq = atoi(pos);
+		if (freq <= 0)
+			return -1;
+	}
+
 	return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
-			     _dev_id, search_delay);
+			     _dev_id, search_delay, seek_count, seek, freq);
+}
+
+
+static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
+{
+	struct p2ps_provision *p2ps_prov;
+	char *pos;
+	size_t info_len = 0;
+	char *info = NULL;
+	u8 role = P2PS_SETUP_NONE;
+	long long unsigned val;
+
+	pos = os_strstr(cmd, "info=");
+	if (pos) {
+		pos += 5;
+		info_len = os_strlen(pos);
+
+		if (info_len) {
+			info = os_malloc(info_len + 1);
+			if (info) {
+				info_len = utf8_unescape(pos, info_len,
+							 info, info_len + 1);
+			} else
+				info_len = 0;
+		}
+	}
+
+	p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
+	if (p2ps_prov == NULL) {
+		os_free(info);
+		return NULL;
+	}
+
+	if (info) {
+		os_memcpy(p2ps_prov->info, info, info_len);
+		p2ps_prov->info[info_len] = '\0';
+		os_free(info);
+	}
+
+	pos = os_strstr(cmd, "status=");
+	if (pos)
+		p2ps_prov->status = atoi(pos + 7);
+	else
+		p2ps_prov->status = -1;
+
+	pos = os_strstr(cmd, "adv_id=");
+	if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
+		goto invalid_args;
+	p2ps_prov->adv_id = val;
+
+	pos = os_strstr(cmd, "method=");
+	if (pos)
+		p2ps_prov->method = strtol(pos + 7, NULL, 16);
+	else
+		p2ps_prov->method = 0;
+
+	pos = os_strstr(cmd, "session=");
+	if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
+		goto invalid_args;
+	p2ps_prov->session_id = val;
+
+	pos = os_strstr(cmd, "adv_mac=");
+	if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
+		goto invalid_args;
+
+	pos = os_strstr(cmd, "session_mac=");
+	if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
+		goto invalid_args;
+
+	/* force conncap with tstCap (no sanity checks) */
+	pos = os_strstr(cmd, "tstCap=");
+	if (pos) {
+		role = strtol(pos + 7, NULL, 16);
+	} else {
+		pos = os_strstr(cmd, "role=");
+		if (pos) {
+			role = strtol(pos + 5, NULL, 16);
+			if (role != P2PS_SETUP_CLIENT &&
+			    role != P2PS_SETUP_GROUP_OWNER)
+				role = P2PS_SETUP_NONE;
+		}
+	}
+	p2ps_prov->role = role;
+
+	return p2ps_prov;
+
+invalid_args:
+	os_free(p2ps_prov);
+	return NULL;
+}
+
+
+static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct p2ps_provision *p2ps_prov;
+	char *pos;
+
+	/* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
+
+	wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+
+	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+	if (!p2ps_prov)
+		return -1;
+
+	if (p2ps_prov->status < 0) {
+		os_free(p2ps_prov);
+		return -1;
+	}
+
+	return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+				  p2ps_prov);
+}
+
+
+static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct p2ps_provision *p2ps_prov;
+	char *pos;
+
+	/* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
+	 *        session=<ses_id> mac=<ses_mac> [info=<infodata>]
+	 */
+
+	wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+
+	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+	if (!p2ps_prov)
+		return -1;
+
+	return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+				  p2ps_prov);
 }
 
 
@@ -4327,10 +4762,18 @@
 	int pd;
 	int ht40, vht;
 
-	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+	if (!wpa_s->global->p2p_init_wpa_s)
+		return -1;
+	if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
+			wpa_s->global->p2p_init_wpa_s->ifname);
+		wpa_s = wpa_s->global->p2p_init_wpa_s;
+	}
+
+	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
 	 * [persistent|persistent=<network id>]
 	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-	 * [ht40] [vht] */
+	 * [ht40] [vht] [auto] */
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -4391,6 +4834,8 @@
 			*pos++ = '\0';
 			if (os_strncmp(pos, "display", 7) == 0)
 				wps_method = WPS_PIN_DISPLAY;
+			else if (os_strncmp(pos, "p2ps", 4) == 0)
+				wps_method = WPS_P2PS;
 		}
 		if (!wps_pin_str_valid(pin)) {
 			os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4457,7 +4902,7 @@
 	else if (os_strstr(pos, " auto") != NULL)
 		use = WPAS_P2P_PD_AUTO;
 
-	return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+	return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
 }
 
 
@@ -4510,6 +4955,40 @@
 	} 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 if (os_strncmp(pos, "asp ", 4) == 0) {
+		char *svc_str;
+		char *svc_info = NULL;
+		u32 id;
+
+		pos += 4;
+		if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
+			return -1;
+
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
+			return -1;
+
+		svc_str = pos + 1;
+
+		pos = os_strchr(svc_str, ' ');
+
+		if (pos)
+			*pos++ = '\0';
+
+		/* All remaining data is the svc_info string */
+		if (pos && pos[0] && pos[0] != ' ') {
+			len = os_strlen(pos);
+
+			/* Unescape in place */
+			len = utf8_unescape(pos, len, pos, len);
+			if (len > 0xff)
+				return -1;
+
+			svc_info = pos;
+		}
+
+		ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
+					      svc_str, svc_info);
 	} else {
 		len = os_strlen(pos);
 		if (len & 1)
@@ -4672,6 +5151,106 @@
 }
 
 
+static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
+				    u8 replace, char *cmd)
+{
+	char *pos;
+	char *adv_str;
+	u32 auto_accept, adv_id, svc_state, config_methods;
+	char *svc_info = NULL;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	/* Auto-Accept value is mandatory, and must be one of the
+	 * single values (0, 1, 2, 4) */
+	auto_accept = atoi(cmd);
+	switch (auto_accept) {
+	case P2PS_SETUP_NONE: /* No auto-accept */
+	case P2PS_SETUP_NEW:
+	case P2PS_SETUP_CLIENT:
+	case P2PS_SETUP_GROUP_OWNER:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Advertisement ID is mandatory */
+	cmd = pos;
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	/* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
+	if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
+		return -1;
+
+	/* Only allow replacements if exist, and adds if not */
+	if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
+		if (!replace)
+			return -1;
+	} else {
+		if (replace)
+			return -1;
+	}
+
+	/* svc_state between 0 - 0xff is mandatory */
+	if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
+		return -1;
+
+	pos = os_strchr(pos, ' ');
+	if (pos == NULL)
+		return -1;
+
+	/* config_methods is mandatory */
+	pos++;
+	if (sscanf(pos, "%x", &config_methods) != 1)
+		return -1;
+
+	if (!(config_methods &
+	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
+		return -1;
+
+	pos = os_strchr(pos, ' ');
+	if (pos == NULL)
+		return -1;
+
+	pos++;
+	adv_str = pos;
+
+	/* Advertisement string is mandatory */
+	if (!pos[0] || pos[0] == ' ')
+		return -1;
+
+	/* Terminate svc string */
+	pos = os_strchr(pos, ' ');
+	if (pos != NULL)
+		*pos++ = '\0';
+
+	/* Service and Response Information are optional */
+	if (pos && pos[0]) {
+		size_t len;
+
+		/* Note the bare ' included, which cannot exist legally
+		 * in unescaped string. */
+		svc_info = os_strstr(pos, "svc_info='");
+
+		if (svc_info) {
+			svc_info += 9;
+			len = os_strlen(svc_info);
+			utf8_unescape(svc_info, len, svc_info, len);
+		}
+	}
+
+	return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
+					(u8) svc_state, (u16) config_methods,
+					svc_info);
+}
+
+
 static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
 	char *pos;
@@ -4685,6 +5264,8 @@
 		return p2p_ctrl_service_add_bonjour(wpa_s, pos);
 	if (os_strcmp(cmd, "upnp") == 0)
 		return p2p_ctrl_service_add_upnp(wpa_s, pos);
+	if (os_strcmp(cmd, "asp") == 0)
+		return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
 	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
 	return -1;
 }
@@ -4732,6 +5313,22 @@
 }
 
 
+static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u32 adv_id;
+
+	if (os_strcmp(cmd, "all") == 0) {
+		wpas_p2p_service_flush_asp(wpa_s);
+		return 0;
+	}
+
+	if (sscanf(cmd, "%x", &adv_id) != 1)
+		return -1;
+
+	return wpas_p2p_service_del_asp(wpa_s, adv_id);
+}
+
+
 static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
 {
 	char *pos;
@@ -4745,6 +5342,25 @@
 		return p2p_ctrl_service_del_bonjour(wpa_s, pos);
 	if (os_strcmp(cmd, "upnp") == 0)
 		return p2p_ctrl_service_del_upnp(wpa_s, pos);
+	if (os_strcmp(cmd, "asp") == 0)
+		return p2p_ctrl_service_del_asp(wpa_s, pos);
+	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "asp") == 0)
+		return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
+
 	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
 	return -1;
 }
@@ -5387,7 +6003,8 @@
 }
 
 
-static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
+				     int only_add)
 {
 	u8 bssid[ETH_ALEN];
 	struct wpa_bss *bss;
@@ -5404,7 +6021,28 @@
 		return -1;
 	}
 
-	return interworking_connect(wpa_s, bss);
+	if (bss->ssid_len == 0) {
+		int found = 0;
+
+		wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
+			   " does not have SSID information", MAC2STR(bssid));
+
+		dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
+					 list) {
+			if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+			    bss->ssid_len > 0) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			return -1;
+		wpa_printf(MSG_DEBUG,
+			   "Found another matching BSS entry with SSID");
+	}
+
+	return interworking_connect(wpa_s, bss, only_add);
 }
 
 
@@ -5861,6 +6499,14 @@
 		pos += ret;
 	}
 
+	if (si.avg_beacon_signal) {
+		ret = os_snprintf(pos, end - pos,
+				  "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
+		if (os_snprintf_error(end - pos, ret))
+			return -1;
+		pos += ret;
+	}
+
 	return pos - buf;
 }
 
@@ -5969,20 +6615,25 @@
 
 static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 {
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
+		wpa_s->global->p2p_init_wpa_s : wpa_s;
+#endif /* CONFIG_P2P */
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
 
 #ifdef CONFIG_P2P
-	wpas_p2p_cancel(wpa_s);
-	wpas_p2p_stop_find(wpa_s);
-	p2p_ctrl_flush(wpa_s);
-	wpas_p2p_group_remove(wpa_s, "*");
-	wpas_p2p_service_flush(wpa_s);
-	wpa_s->global->p2p_disabled = 0;
-	wpa_s->global->p2p_per_sta_psk = 0;
-	wpa_s->conf->num_sec_device_types = 0;
-	wpa_s->p2p_disable_ip_addr_req = 0;
-	os_free(wpa_s->global->p2p_go_avoid_freq.range);
-	wpa_s->global->p2p_go_avoid_freq.range = NULL;
+	wpas_p2p_cancel(p2p_wpa_s);
+	p2p_ctrl_flush(p2p_wpa_s);
+	wpas_p2p_group_remove(p2p_wpa_s, "*");
+	wpas_p2p_service_flush(p2p_wpa_s);
+	p2p_wpa_s->global->p2p_disabled = 0;
+	p2p_wpa_s->global->p2p_per_sta_psk = 0;
+	p2p_wpa_s->conf->num_sec_device_types = 0;
+	p2p_wpa_s->p2p_disable_ip_addr_req = 0;
+	os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
+	p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
+	p2p_wpa_s->global->pending_p2ps_group = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
@@ -6011,6 +6662,7 @@
 	wpa_supplicant_stop_countermeasures(wpa_s, NULL);
 
 	wpa_s->no_keep_alive = 0;
+	wpa_s->own_disconnect_req = 0;
 
 	os_free(wpa_s->disallow_aps_bssid);
 	wpa_s->disallow_aps_bssid = NULL;
@@ -6023,8 +6675,6 @@
 	wpa_s->sta_uapsd = 0;
 
 	wpa_drv_radio_disable(wpa_s, 0);
-
-	wpa_bss_flush(wpa_s);
 	wpa_blacklist_clear(wpa_s);
 	wpa_s->extra_blacklist_count = 0;
 	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
@@ -6054,11 +6704,24 @@
 	wpa_s->ext_eapol_frame_io = 0;
 #ifdef CONFIG_TESTING_OPTIONS
 	wpa_s->extra_roc_dur = 0;
+	wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_s->disconnected = 0;
 	os_free(wpa_s->next_scan_freqs);
 	wpa_s->next_scan_freqs = NULL;
+
+	wpa_bss_flush(wpa_s);
+	if (!dl_list_empty(&wpa_s->bss)) {
+		wpa_printf(MSG_DEBUG,
+			   "BSS table not empty after flush: %u entries, current_bss=%p bssid="
+			   MACSTR " pending_bssid=" MACSTR,
+			   dl_list_len(&wpa_s->bss), wpa_s->current_bss,
+			   MAC2STR(wpa_s->bssid),
+			   MAC2STR(wpa_s->pending_bssid));
+	}
+
+	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
 }
 
 
@@ -6305,6 +6968,15 @@
 		return;
 	}
 
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
+		wpa_printf(MSG_DEBUG,
+			   "Interworking select in progress - reject new scan");
+		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+		return;
+	}
+#endif /* CONFIG_INTERWORKING */
+
 	if (params) {
 		if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
 			scan_only = 1;
@@ -6761,6 +7433,44 @@
 	return res < 0 ? -1 : 0;
 }
 
+
+static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+	extern char wpa_trace_fail_func[256];
+	extern unsigned int wpa_trace_fail_after;
+	char *pos;
+
+	wpa_trace_fail_after = atoi(cmd);
+	pos = os_strchr(cmd, ':');
+	if (pos) {
+		pos++;
+		os_strlcpy(wpa_trace_fail_func, pos,
+			   sizeof(wpa_trace_fail_func));
+	} else {
+		wpa_trace_fail_after = 0;
+	}
+	return 0;
+#else /* WPA_TRACE_BFD */
+	return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
+				    char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+	extern char wpa_trace_fail_func[256];
+	extern unsigned int wpa_trace_fail_after;
+
+	return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
+			   wpa_trace_fail_func);
+#else /* WPA_TRACE_BFD */
+	return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -6997,7 +7707,7 @@
 
 	if (os_strncmp(cmd, " ssid=", 6) == 0) {
 		ssid.ssid_len = os_strlen(cmd + 6);
-		if (ssid.ssid_len > 32)
+		if (ssid.ssid_len > SSID_MAX_LEN)
 			return -1;
 		ssid.ssid = (u8 *) (cmd + 6);
 		ssid_p = &ssid;
@@ -7018,6 +7728,126 @@
 }
 
 
+static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	char *token, *context = NULL;
+	unsigned int enable = ~0, type = 0;
+	u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
+	u8 *addr = NULL, *mask = NULL;
+
+	while ((token = str_token(cmd, " ", &context))) {
+		if (os_strcasecmp(token, "scan") == 0) {
+			type |= MAC_ADDR_RAND_SCAN;
+		} else if (os_strcasecmp(token, "sched") == 0) {
+			type |= MAC_ADDR_RAND_SCHED_SCAN;
+		} else if (os_strcasecmp(token, "pno") == 0) {
+			type |= MAC_ADDR_RAND_PNO;
+		} else if (os_strcasecmp(token, "all") == 0) {
+			type = wpa_s->mac_addr_rand_supported;
+		} else if (os_strncasecmp(token, "enable=", 7) == 0) {
+			enable = atoi(token + 7);
+		} else if (os_strncasecmp(token, "addr=", 5) == 0) {
+			addr = _addr;
+			if (hwaddr_aton(token + 5, addr)) {
+				wpa_printf(MSG_INFO,
+					   "CTRL: Invalid MAC address: %s",
+					   token);
+				return -1;
+			}
+		} else if (os_strncasecmp(token, "mask=", 5) == 0) {
+			mask = _mask;
+			if (hwaddr_aton(token + 5, mask)) {
+				wpa_printf(MSG_INFO,
+					   "CTRL: Invalid MAC address mask: %s",
+					   token);
+				return -1;
+			}
+		} else {
+			wpa_printf(MSG_INFO,
+				   "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
+				   token);
+			return -1;
+		}
+	}
+
+	if (!type) {
+		wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
+		return -1;
+	}
+
+	if ((wpa_s->mac_addr_rand_supported & type) != type) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
+			   type, wpa_s->mac_addr_rand_supported);
+		return -1;
+	}
+
+	if (enable > 1) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
+		return -1;
+	}
+
+	if (!enable) {
+		wpas_mac_addr_rand_scan_clear(wpa_s, type);
+		if (wpa_s->pno) {
+			if (type & MAC_ADDR_RAND_PNO) {
+				wpas_stop_pno(wpa_s);
+				wpas_start_pno(wpa_s);
+			}
+		} else if (wpa_s->sched_scanning &&
+			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+			/* simulate timeout to restart the sched scan */
+			wpa_s->sched_scan_timed_out = 1;
+			wpa_s->prev_sched_ssid = NULL;
+			wpa_supplicant_cancel_sched_scan(wpa_s);
+		}
+		return 0;
+	}
+
+	if ((addr && !mask) || (!addr && mask)) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
+		return -1;
+	}
+
+	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN cannot allow multicast address");
+		return -1;
+	}
+
+	if (type & MAC_ADDR_RAND_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+					    addr, mask);
+	}
+
+	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+					    addr, mask);
+
+		if (wpa_s->sched_scanning && !wpa_s->pno) {
+			/* simulate timeout to restart the sched scan */
+			wpa_s->sched_scan_timed_out = 1;
+			wpa_s->prev_sched_ssid = NULL;
+			wpa_supplicant_cancel_sched_scan(wpa_s);
+		}
+	}
+
+	if (type & MAC_ADDR_RAND_PNO) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+					    addr, mask);
+		if (wpa_s->pno) {
+			wpas_stop_pno(wpa_s);
+			wpas_start_pno(wpa_s);
+		}
+	}
+
+	return 0;
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
 {
@@ -7085,6 +7915,9 @@
 	} else if (os_strncmp(buf, "SET ", 4) == 0) {
 		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "DUMP", 4) == 0) {
+		reply_len = wpa_config_dump_values(wpa_s->conf,
+						   reply, reply_size);
 	} else if (os_strncmp(buf, "GET ", 4) == 0) {
 		reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
 							  reply, reply_size);
@@ -7249,13 +8082,19 @@
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
-		if (p2p_ctrl_find(wpa_s, buf + 9))
+		if (p2p_ctrl_find(wpa_s, buf + 8))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_FIND") == 0) {
 		if (p2p_ctrl_find(wpa_s, ""))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
 		wpas_p2p_stop_find(wpa_s);
+	} else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
+		if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
+		if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
+			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
 		reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
 					     reply_size);
@@ -7301,6 +8140,9 @@
 	} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
 		if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
+		if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
+			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
 		if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
 			reply_len = -1;
@@ -7358,8 +8200,19 @@
 		if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
 			reply_len = -1;
 	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
-		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+		if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
+		int id;
+
+		id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
+		if (id < 0)
+			reply_len = -1;
+		else {
+			reply_len = os_snprintf(reply, reply_size, "%d\n", id);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
 	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
 		if (get_anqp(wpa_s, buf + 9) < 0)
 			reply_len = -1;
@@ -7429,6 +8282,7 @@
 		wpa_supplicant_cancel_scan(wpa_s);
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
+		eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
 	} else if (os_strcmp(buf, "SCAN") == 0) {
 		wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
 	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -7517,6 +8371,9 @@
 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
 		if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
 			reply_len = -1;
+	} else if (os_strcmp(buf, "STOP_AP") == 0) {
+		if (wpas_ap_stop_ap(wpa_s))
+			reply_len = -1;
 #endif /* CONFIG_AP */
 	} else if (os_strcmp(buf, "SUSPEND") == 0) {
 		wpas_notify_suspend(wpa_s->global);
@@ -7550,6 +8407,14 @@
 	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
 		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
+								      buf + 24))
+			reply_len = -1;
 #endif /* CONFIG_TDLS */
 	} else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
 		reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
@@ -7585,8 +8450,8 @@
 	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
 		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
 			reply_len = -1;
-	} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
-		if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+	} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
+		if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
 				reply_len = -1;
 #endif /* CONFIG_WNM */
 	} else if (os_strcmp(buf, "FLUSH") == 0) {
@@ -7615,6 +8480,11 @@
 	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
 		if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+		if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+		reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
 		if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -7630,6 +8500,9 @@
 			reply_len = -1;
 	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
 		wpas_ctrl_iface_erp_flush(wpa_s);
+	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
+		if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -7649,11 +8522,14 @@
 					   char *cmd)
 {
 	struct wpa_interface iface;
-	char *pos;
+	char *pos, *extra;
+	struct wpa_supplicant *wpa_s;
+	unsigned int create_iface = 0;
+	u8 mac_addr[ETH_ALEN];
 
 	/*
 	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
-	 * TAB<bridge_ifname>
+	 * TAB<bridge_ifname>[TAB<create>]
 	 */
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
 
@@ -7713,12 +8589,54 @@
 			iface.bridge_ifname = NULL;
 		if (pos == NULL)
 			break;
+
+		extra = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (!extra[0])
+			break;
+
+		if (os_strcmp(extra, "create") == 0)
+			create_iface = 1;
+		else {
+			wpa_printf(MSG_DEBUG,
+				   "INTERFACE_ADD unsupported extra parameter: '%s'",
+				   extra);
+			return -1;
+		}
 	} while (0);
 
-	if (wpa_supplicant_get_iface(global, iface.ifname))
-		return -1;
+	if (create_iface) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
+			   iface.ifname);
+		if (!global->ifaces)
+			return -1;
+		if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+				   NULL, NULL, NULL, mac_addr, NULL) < 0) {
+			wpa_printf(MSG_ERROR,
+				   "CTRL_IFACE interface creation failed");
+			return -1;
+		}
 
-	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE interface '%s' created with MAC addr: "
+			   MACSTR, iface.ifname, MAC2STR(mac_addr));
+	}
+
+	if (wpa_supplicant_get_iface(global, iface.ifname))
+		goto fail;
+
+	wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+	if (!wpa_s)
+		goto fail;
+	wpa_s->added_vif = create_iface;
+	return 0;
+
+fail:
+	if (create_iface)
+		wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
+	return -1;
 }
 
 
@@ -7726,13 +8644,22 @@
 					      char *cmd)
 {
 	struct wpa_supplicant *wpa_s;
+	int ret;
+	unsigned int delete_iface;
 
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
 
 	wpa_s = wpa_supplicant_get_iface(global, cmd);
 	if (wpa_s == NULL)
 		return -1;
-	return wpa_supplicant_remove_iface(global, wpa_s, 0);
+	delete_iface = wpa_s->added_vif;
+	ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
+	if (!ret && delete_iface) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
+			   cmd);
+		ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
+	}
+	return ret;
 }
 
 
@@ -7878,6 +8805,7 @@
 		"P2P_SERV_DISC_EXTERNAL ",
 		"P2P_SERVICE_ADD ",
 		"P2P_SERVICE_DEL ",
+		"P2P_SERVICE_REP ",
 		"P2P_REJECT ",
 		"P2P_INVITE ",
 		"P2P_PEER ",
@@ -7886,9 +8814,13 @@
 		"P2P_PRESENCE_REQ ",
 		"P2P_EXT_LISTEN ",
 		"P2P_REMOVE_CLIENT ",
+		"WPS_NFC_TOKEN ",
+		"WPS_NFC_TAG_READ ",
 		"NFC_GET_HANDOVER_SEL ",
 		"NFC_GET_HANDOVER_REQ ",
 		"NFC_REPORT_HANDOVER ",
+		"P2P_ASP_PROVISION ",
+		"P2P_ASP_PROVISION_RESP ",
 		NULL
 	};
 	int found = 0;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 2c1c6a0..b1ac766 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -74,7 +74,7 @@
 
 static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
 					    struct sockaddr_un *from,
-					    socklen_t fromlen)
+					    socklen_t fromlen, int global)
 {
 	struct wpa_ctrl_dst *dst;
 	char addr_txt[200];
@@ -89,7 +89,8 @@
 	printf_encode(addr_txt, sizeof(addr_txt),
 		      (u8 *) from->sun_path,
 		      fromlen - offsetof(struct sockaddr_un, sun_path));
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
+		   global ? "global " : "", addr_txt);
 	return 0;
 }
 
@@ -174,7 +175,7 @@
 
 	if (os_strcmp(buf, "ATTACH") == 0) {
 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
-						     fromlen))
+						     fromlen, 0))
 			reply_len = 1;
 		else {
 			new_attached = 1;
@@ -775,7 +776,8 @@
 		if (os_strcmp(buf, "ATTACH") == 0) {
 			/* handle ATTACH signal of first monitor interface */
 			if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
-							      &from, fromlen)) {
+							      &from, fromlen,
+							      0)) {
 				if (sendto(priv->sock, "OK\n", 3, 0,
 					   (struct sockaddr *) &from, fromlen) <
 				    0) {
@@ -830,7 +832,7 @@
 
 	if (os_strcmp(buf, "ATTACH") == 0) {
 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
-						     fromlen))
+						     fromlen, 1))
 			reply_len = 1;
 		else
 			reply_len = 2;
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5cc1505..7ef6cad 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -165,6 +165,7 @@
 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
+
 	if (!dbus_timeout_get_enabled(timeout))
 		return TRUE;
 
@@ -180,6 +181,7 @@
 static void remove_timeout(DBusTimeout *timeout, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
+
 	eloop_cancel_timeout(process_timeout, priv, timeout);
 	dbus_timeout_set_data(timeout, NULL, NULL);
 }
@@ -244,8 +246,7 @@
 						   remove_timeout,
 						   timeout_toggled, priv,
 						   NULL)) {
-		wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
-			   "functions");
+		wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
 		return -1;
 	}
 
@@ -259,12 +260,12 @@
 
 
 static DBusHandlerResult disconnect_filter(DBusConnection *conn,
-                                           DBusMessage *message, void *data)
+					   DBusMessage *message, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
 
 	if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
-	                           "Disconnected")) {
+				   "Disconnected")) {
 		wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
 		dbus_connection_set_exit_on_disconnect(conn, FALSE);
 		wpa_supplicant_terminate_proc(priv->global);
@@ -284,10 +285,11 @@
 	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
 	if (priv->con) {
 		dbus_connection_add_filter(priv->con, disconnect_filter, priv,
-		                           NULL);
+					   NULL);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
-			   "bus: %s - %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not acquire the system bus: %s - %s",
+			   error.name, error.message);
 		ret = -1;
 	}
 	dbus_error_free(&error);
@@ -309,7 +311,7 @@
 	 * FIXME: is there a better solution to this problem?
 	 */
 	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
-	                       priv->con, NULL);
+			       priv->con, NULL);
 
 	return 0;
 }
@@ -345,26 +347,14 @@
 		return NULL;
 	priv->global = global;
 
-	if (wpas_dbus_init_common(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-
+	if (wpas_dbus_init_common(priv) < 0 ||
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-	if (wpas_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
+	    wpas_dbus_ctrl_iface_init(priv) < 0 ||
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
 #ifdef CONFIG_CTRL_IFACE_DBUS
-	if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
+	    wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
 #endif /* CONFIG_CTRL_IFACE_DBUS */
-
-	if (wpas_dbus_init_common_finish(priv) < 0) {
+	    wpas_dbus_init_common_finish(priv) < 0) {
 		wpas_dbus_deinit(priv);
 		return NULL;
 	}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 034b751..a0c44eb 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -66,7 +66,7 @@
 
 const char * wpa_dbus_type_as_string(const int type)
 {
-	switch(type) {
+	switch (type) {
 	case DBUS_TYPE_BYTE:
 		return DBUS_TYPE_BYTE_AS_STRING;
 	case DBUS_TYPE_BOOLEAN:
@@ -106,11 +106,8 @@
 					      iter_dict_entry))
 		return FALSE;
 
-	if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
-					    &key))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+					      &key);
 }
 
 
@@ -120,10 +117,8 @@
 {
 	if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
 		return FALSE;
-	if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
-		return FALSE;
 
-	return TRUE;
+	return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
 }
 
 
@@ -143,22 +138,15 @@
 		return FALSE;
 
 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, value_type))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					    key, value_type) ||
+	    !dbus_message_iter_open_container(&iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
-					      type_as_string, &iter_dict_val))
+					      type_as_string, &iter_dict_val) ||
+	    !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
 		return FALSE;
 
-	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					    &iter_dict_val);
 }
 
 
@@ -170,17 +158,13 @@
 	dbus_uint32_t i;
 
 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY) ||
+	    !dbus_message_iter_open_container(&iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &iter_dict_val))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+					      &iter_dict_val) ||
+	    !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &iter_array))
 		return FALSE;
@@ -195,11 +179,8 @@
 	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
 		return FALSE;
 
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					    &iter_dict_val);
 }
 
 
@@ -428,9 +409,7 @@
 					    const char *value,
 					    const dbus_uint32_t value_len)
 {
-	if (!key)
-		return FALSE;
-	if (!value && (value_len != 0))
+	if (!key || (!value && value_len != 0))
 		return FALSE;
 	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
 						   value_len);
@@ -468,24 +447,17 @@
 	if (os_snprintf_error(sizeof(array_type), err))
 		return FALSE;
 
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_dict_entry,
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+	    !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY) ||
+	    !dbus_message_iter_open_container(iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
 					      array_type,
 					      iter_dict_val))
 		return FALSE;
 
-	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
-					      type, iter_array))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+						type, iter_array);
 }
 
 
@@ -542,10 +514,8 @@
 	DBusMessageIter iter_bytes;
 	size_t i;
 
-	if (!iter_array || !value)
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+	if (!iter_array || !value ||
+	    !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &iter_bytes))
 		return FALSE;
@@ -557,10 +527,7 @@
 			return FALSE;
 	}
 
-	if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_close_container(iter_array, &iter_bytes);
 }
 
 
@@ -586,17 +553,12 @@
 				    DBusMessageIter *iter_dict_val,
 				    DBusMessageIter *iter_array)
 {
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+	    !dbus_message_iter_close_container(iter_dict_val, iter_array))
 		return FALSE;
 
-	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
-					  iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+					    iter_dict_val);
 }
 
 
@@ -619,12 +581,8 @@
 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
 	dbus_uint32_t i;
 
-	if (!key)
-		return FALSE;
-	if (!items && (num_items != 0))
-		return FALSE;
-
-	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+	if (!key || (!items && num_items != 0) ||
+	    !wpa_dbus_dict_begin_string_array(iter_dict, key,
 					      &iter_dict_entry, &iter_dict_val,
 					      &iter_array))
 		return FALSE;
@@ -635,11 +593,8 @@
 			return FALSE;
 	}
 
-	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
-					    &iter_dict_val, &iter_array))
-		return FALSE;
-
-	return TRUE;
+	return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+					      &iter_dict_val, &iter_array);
 }
 
 
@@ -662,12 +617,9 @@
 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
 	dbus_uint32_t i;
 
-	if (!key)
-		return FALSE;
-	if (!items && (num_items != 0))
-		return FALSE;
-
-	if (!wpa_dbus_dict_begin_array(iter_dict, key,
+	if (!key ||
+	    (!items && num_items != 0) ||
+	    !wpa_dbus_dict_begin_array(iter_dict, key,
 				       DBUS_TYPE_ARRAY_AS_STRING
 				       DBUS_TYPE_BYTE_AS_STRING,
 				       &iter_dict_entry, &iter_dict_val,
@@ -681,11 +633,8 @@
 			return FALSE;
 	}
 
-	if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
-				     &iter_dict_val, &iter_array))
-		return FALSE;
-
-	return TRUE;
+	return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+				       &iter_dict_val, &iter_array);
 }
 
 
@@ -707,16 +656,25 @@
 				    DBusMessageIter *iter_dict,
 				    DBusError *error)
 {
+	int type;
+
+	wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
 	if (!iter || !iter_dict) {
 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
-		                     "[internal] missing message iterators");
+				     "[internal] missing message iterators");
 		return FALSE;
 	}
 
-	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+	type = dbus_message_iter_get_arg_type(iter);
+	if (type != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: unexpected message argument types (arg=%c element=%c)",
+			   __func__, type,
+			   type != DBUS_TYPE_ARRAY ? '?' :
+			   dbus_message_iter_get_element_type(iter));
 		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
-		                     "unexpected message argument types");
+				     "unexpected message argument types");
 		return FALSE;
 	}
 
@@ -742,7 +700,6 @@
 	if (!buffer)
 		return FALSE;
 
-	entry->bytearray_value = buffer;
 	entry->array_len = 0;
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
 		char byte;
@@ -753,21 +710,22 @@
 				BYTE_ARRAY_ITEM_SIZE);
 			if (nbuffer == NULL) {
 				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_byte_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s out of memory trying to retrieve the string array",
+					   __func__);
 				goto done;
 			}
 			buffer = nbuffer;
 		}
-		entry->bytearray_value = buffer;
 
 		dbus_message_iter_get_basic(iter, &byte);
-		entry->bytearray_value[count] = byte;
+		buffer[count] = byte;
 		entry->array_len = ++count;
 		dbus_message_iter_next(iter);
 	}
+	entry->bytearray_value = buffer;
+	wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
+			entry->bytearray_value, entry->array_len);
 
 	/* Zero-length arrays are valid. */
 	if (entry->array_len == 0) {
@@ -790,18 +748,16 @@
 	struct wpa_dbus_dict_entry *entry)
 {
 	dbus_uint32_t count = 0;
-	dbus_bool_t success = FALSE;
 	char **buffer, **nbuffer;
 
 	entry->strarray_value = NULL;
+	entry->array_len = 0;
 	entry->array_type = DBUS_TYPE_STRING;
 
 	buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
 	if (buffer == NULL)
 		return FALSE;
 
-	entry->strarray_value = buffer;
-	entry->array_len = 0;
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
 		const char *value;
 		char *str;
@@ -811,29 +767,31 @@
 				buffer, count + STR_ARRAY_CHUNK_SIZE,
 				STR_ARRAY_ITEM_SIZE);
 			if (nbuffer == NULL) {
-				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_string_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
-				goto done;
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s out of memory trying to retrieve the string array",
+					   __func__);
+				goto fail;
 			}
 			buffer = nbuffer;
 		}
-		entry->strarray_value = buffer;
 
 		dbus_message_iter_get_basic(iter, &value);
+		wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
+			   __func__, wpa_debug_show_keys ? value : "[omitted]");
 		str = os_strdup(value);
 		if (str == NULL) {
-			wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
-				   "string_array out of memory trying to "
-				   "duplicate the string array");
-			goto done;
+			wpa_printf(MSG_ERROR,
+				   "dbus: %s out of memory trying to duplicate the string array",
+				   __func__);
+			goto fail;
 		}
-		entry->strarray_value[count] = str;
-		entry->array_len = ++count;
+		buffer[count++] = str;
 		dbus_message_iter_next(iter);
 	}
+	entry->strarray_value = buffer;
+	entry->array_len = count;
+	wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
+		   __func__, entry->array_len);
 
 	/* Zero-length arrays are valid. */
 	if (entry->array_len == 0) {
@@ -841,10 +799,15 @@
 		entry->strarray_value = NULL;
 	}
 
-	success = TRUE;
+	return TRUE;
 
-done:
-	return success;
+fail:
+	while (count > 0) {
+		count--;
+		os_free(buffer[count]);
+	}
+	os_free(buffer);
+	return FALSE;
 }
 
 
@@ -856,15 +819,31 @@
 {
 	struct wpa_dbus_dict_entry tmpentry;
 	size_t buflen = 0;
-	int i;
-
-	if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
-		return FALSE;
+	int i, type;
 
 	entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
 	entry->array_len = 0;
 	entry->binarray_value = NULL;
 
+	type = dbus_message_iter_get_arg_type(iter);
+	wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
+	if (type == DBUS_TYPE_INVALID) {
+		/* Likely an empty array of arrays */
+		return TRUE;
+	}
+	if (type != DBUS_TYPE_ARRAY) {
+		wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
+			   __func__, type);
+		return FALSE;
+	}
+
+	type = dbus_message_iter_get_element_type(iter);
+	if (type != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
+			   __func__, type);
+		return FALSE;
+	}
+
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
 		DBusMessageIter iter_array;
 
@@ -884,7 +863,7 @@
 		os_memset(&tmpentry, 0, sizeof(tmpentry));
 		tmpentry.type = DBUS_TYPE_ARRAY;
 		if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
-					== FALSE)
+		    == FALSE)
 			goto cleanup;
 
 		entry->binarray_value[entry->array_len] =
@@ -897,6 +876,8 @@
 		entry->array_len++;
 		dbus_message_iter_next(iter);
 	}
+	wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
+		   __func__, entry->array_len);
 
 	return TRUE;
 
@@ -917,12 +898,11 @@
 	dbus_bool_t success = FALSE;
 	DBusMessageIter iter_array;
 
-	if (!entry)
-		return FALSE;
+	wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
 
 	dbus_message_iter_recurse(iter_dict_val, &iter_array);
 
- 	switch (array_type) {
+	switch (array_type) {
 	case DBUS_TYPE_BYTE:
 		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
 							      entry);
@@ -936,6 +916,8 @@
 		success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
 		break;
 	default:
+		wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
+			   __func__, array_type);
 		break;
 	}
 
@@ -950,42 +932,72 @@
 
 	switch (entry->type) {
 	case DBUS_TYPE_OBJECT_PATH:
+		dbus_message_iter_get_basic(iter, &v);
+		wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
+			   __func__, v);
+		entry->str_value = os_strdup(v);
+		if (entry->str_value == NULL)
+			return FALSE;
+		break;
 	case DBUS_TYPE_STRING:
 		dbus_message_iter_get_basic(iter, &v);
+		wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
+			   __func__, wpa_debug_show_keys ? v : "[omitted]");
 		entry->str_value = os_strdup(v);
 		if (entry->str_value == NULL)
 			return FALSE;
 		break;
 	case DBUS_TYPE_BOOLEAN:
 		dbus_message_iter_get_basic(iter, &entry->bool_value);
+		wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
+			   __func__, entry->bool_value);
 		break;
 	case DBUS_TYPE_BYTE:
 		dbus_message_iter_get_basic(iter, &entry->byte_value);
+		wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
+			   __func__, entry->byte_value);
 		break;
 	case DBUS_TYPE_INT16:
 		dbus_message_iter_get_basic(iter, &entry->int16_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
+			   __func__, entry->int16_value);
 		break;
 	case DBUS_TYPE_UINT16:
 		dbus_message_iter_get_basic(iter, &entry->uint16_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
+			   __func__, entry->uint16_value);
 		break;
 	case DBUS_TYPE_INT32:
 		dbus_message_iter_get_basic(iter, &entry->int32_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
+			   __func__, entry->int32_value);
 		break;
 	case DBUS_TYPE_UINT32:
 		dbus_message_iter_get_basic(iter, &entry->uint32_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
+			   __func__, entry->uint32_value);
 		break;
 	case DBUS_TYPE_INT64:
 		dbus_message_iter_get_basic(iter, &entry->int64_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
+			   __func__, (long long int) entry->int64_value);
 		break;
 	case DBUS_TYPE_UINT64:
 		dbus_message_iter_get_basic(iter, &entry->uint64_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
+			   __func__,
+			   (unsigned long long int) entry->uint64_value);
 		break;
 	case DBUS_TYPE_DOUBLE:
 		dbus_message_iter_get_basic(iter, &entry->double_value);
+		wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
+			   __func__, entry->double_value);
 		break;
 	case DBUS_TYPE_ARRAY:
 		return _wpa_dbus_dict_entry_get_array(iter, entry);
 	default:
+		wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
+			   __func__, entry->type);
 		return FALSE;
 	}
 
@@ -1016,26 +1028,40 @@
 	int type;
 	const char *key;
 
-	if (!iter_dict || !entry)
+	if (!iter_dict || !entry ||
+	    dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
+		wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
 		goto error;
-
-	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
-		goto error;
+	}
 
 	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
 	dbus_message_iter_get_basic(&iter_dict_entry, &key);
+	wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
 	entry->key = key;
 
-	if (!dbus_message_iter_next(&iter_dict_entry))
+	if (!dbus_message_iter_next(&iter_dict_entry)) {
+		wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
 		goto error;
+	}
 	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
-	if (type != DBUS_TYPE_VARIANT)
+	if (type != DBUS_TYPE_VARIANT) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: unexpected dict entry variant type: %c",
+			   __func__, type);
 		goto error;
+	}
 
 	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
 	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
-	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+	wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
+		   __func__, entry->type);
+	entry->array_type = DBUS_TYPE_INVALID;
+	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: failed to fetch dict values from variant",
+			   __func__);
 		goto error;
+	}
 
 	dbus_message_iter_next(iter_dict);
 	return TRUE;
@@ -1090,6 +1116,8 @@
 			os_free(entry->bytearray_value);
 			break;
 		case DBUS_TYPE_STRING:
+			if (!entry->strarray_value)
+				break;
 			for (i = 0; i < entry->array_len; i++)
 				os_free(entry->strarray_value[i]);
 			os_free(entry->strarray_value);
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 9666349..b068431 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -72,28 +72,28 @@
 
 /* Manual construction and addition of array elements */
 dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
-                                      const char *key, const char *type,
-                                      DBusMessageIter *iter_dict_entry,
-                                      DBusMessageIter *iter_dict_val,
-                                      DBusMessageIter *iter_array);
+				      const char *key, const char *type,
+				      DBusMessageIter *iter_dict_entry,
+				      DBusMessageIter *iter_dict_val,
+				      DBusMessageIter *iter_array);
 
 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-                                             const char *key,
-                                             DBusMessageIter *iter_dict_entry,
-                                             DBusMessageIter *iter_dict_val,
-                                             DBusMessageIter *iter_array);
+					     const char *key,
+					     DBusMessageIter *iter_dict_entry,
+					     DBusMessageIter *iter_dict_val,
+					     DBusMessageIter *iter_array);
 
 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
-                                             const char *elem);
+						   const char *elem);
 
 dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
 						const u8 *value,
 						size_t value_len);
 
 dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
-                                    DBusMessageIter *iter_dict_entry,
-                                    DBusMessageIter *iter_dict_val,
-                                    DBusMessageIter *iter_array);
+				    DBusMessageIter *iter_dict_entry,
+				    DBusMessageIter *iter_dict_val,
+				    DBusMessageIter *iter_array);
 
 static inline dbus_bool_t
 wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
@@ -120,7 +120,11 @@
  * Reading a dict from a DBusMessage
  */
 
-#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+/*
+ * Used only in struct wpa_dbus_dict_entry::array_type internally to identify
+ * special binary array case.
+ */
+#define WPAS_DBUS_TYPE_BINARRAY ((int) '@')
 
 struct wpa_dbus_dict_entry {
 	int type;         /** the dbus type of the dict entry's value */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index cbf9d32..30ef03a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -75,8 +75,7 @@
 			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 		}
 
-		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
-		{
+		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 			if (wpa_s->preq_notify_peer != NULL &&
 			    os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
 			    (new_owner == NULL || os_strlen(new_owner) == 0)) {
@@ -148,22 +147,14 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &wpa_s->dbus_new_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, wpa_s->dbus_new_path,
-			    WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &wpa_s->dbus_new_path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, wpa_s->dbus_new_path,
+		     WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -229,7 +220,7 @@
 
 
 /**
- * wpas_dbus_signal_blob - Send a BSS related event signal
+ * wpas_dbus_signal_bss - Send a BSS related event signal
  * @wpa_s: %wpa_supplicant network interface data
  * @bss_obj_path: BSS object path
  * @sig_name: signal name - BSSAdded or BSSRemoved
@@ -259,22 +250,14 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &bss_obj_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
-						    WPAS_DBUS_NEW_IFACE_BSS,
-						    &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &bss_obj_path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(iface, bss_obj_path,
+					     WPAS_DBUS_NEW_IFACE_BSS,
+					     &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -407,23 +390,14 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = net_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
-			    &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+		     &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -513,19 +487,12 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &net_ptr))
-		goto err;
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
-		goto err;
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &net_ptr) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -543,6 +510,7 @@
 {
 
 	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
 		    wpa_s->dbus_new_path, ssid->id);
@@ -749,15 +717,11 @@
 	if (cred->encr_type & WPS_ENCR_AES)
 		encr_type[et_num++] = "aes";
 
-	if (wpa_s->current_ssid) {
-		if (!wpa_dbus_dict_append_byte_array(
-			    &dict_iter, "BSSID",
-			    (const char *) wpa_s->current_ssid->bssid,
-			    ETH_ALEN))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+	if ((wpa_s->current_ssid &&
+	     !wpa_dbus_dict_append_byte_array(
+		     &dict_iter, "BSSID",
+		     (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
 					     (const char *) cred->ssid,
 					     cred->ssid_len) ||
 	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
@@ -784,6 +748,8 @@
 
 void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
 				    int depth, const char *subject,
+				    const char *altsubject[],
+				    int num_altsubject,
 				    const char *cert_hash,
 				    const struct wpabuf *cert)
 {
@@ -804,29 +770,23 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
-	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
-		goto nomem;
-
-	if (cert_hash &&
-	    !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
-		goto nomem;
-
-	if (cert &&
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
-					     wpabuf_head(cert),
-					     wpabuf_len(cert)))
-		goto nomem;
-
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
+	    (altsubject && num_altsubject &&
+	     !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
+						altsubject, num_altsubject)) ||
+	    (cert_hash &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
+					  cert_hash)) ||
+	    (cert &&
+	     !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+					      wpabuf_head(cert),
+					      wpabuf_len(cert))) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -852,15 +812,12 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
-	    ||
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
 	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
 					    &parameter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -946,7 +903,6 @@
 void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
 					const char *role)
 {
-	int error = 1;
 	DBusMessage *msg;
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
@@ -970,30 +926,17 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter,
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter,
 					      "interface_object",
-					      wpa_s->dbus_new_path))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_string(&dict_iter, "role", role))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+					      wpa_s->dbus_new_path) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	error = 0;
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
-	if (error > 0)
-		wpa_printf(MSG_ERROR,
-			   "dbus: Failed to construct GroupFinished");
-
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1056,9 +999,10 @@
 				   "ProvisionDiscoveryPBCResponse";
 		else
 			return; /* Unknown or un-supported method */
-	} else if (!request && status)
+	} else {
 		/* Explicit check for failure response */
 		_signal = "ProvisionDiscoveryFailure";
+	}
 
 	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
 		   (!request && !status &&
@@ -1279,34 +1223,26 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
 	/*
 	 * In case the device supports creating a separate interface the
 	 * DBus client will need to know the object path for the interface
 	 * object this group was created on, so include it here.
 	 */
-	if (!wpa_dbus_dict_append_object_path(&dict_iter,
-					"interface_object",
-					wpa_s->dbus_new_path))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_string(&dict_iter, "role",
-					 client ? "client" : "GO"))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter,
+					      "interface_object",
+					      wpa_s->dbus_new_path) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "role",
+					 client ? "client" : "GO") ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
-	   !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	if (client)
-		peer_groups_changed(wpa_s);
-
-nomem:
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		if (client)
+			peer_groups_changed(wpa_s);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1352,9 +1288,8 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto err;
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
 		goto err;
@@ -1363,15 +1298,10 @@
 		int i = 0;
 		int freq_list_num = 0;
 
-		if (res->role_go) {
-			if (!wpa_dbus_dict_append_byte_array(
-				    &dict_iter, "passphrase",
-				    (const char *) res->passphrase,
-				    sizeof(res->passphrase)))
-				goto err;
-		}
-
-		if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+		if ((res->role_go &&
+		     !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
+						  res->passphrase)) ||
+		    !wpa_dbus_dict_append_string(&dict_iter, "role_go",
 						 res->role_go ? "GO" :
 						 "client") ||
 		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
@@ -1406,22 +1336,16 @@
 					       DBUS_TYPE_INT32_AS_STRING,
 					       &iter_dict_entry,
 					       &iter_dict_val,
-					       &iter_dict_array))
-			goto err;
-
-		if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+					       &iter_dict_array) ||
+		    !dbus_message_iter_append_fixed_array(&iter_dict_array,
 							  DBUS_TYPE_INT32,
 							  &f_array,
-							  freq_list_num))
-			goto err;
-
-		if (!wpa_dbus_dict_end_array(&dict_iter,
+							  freq_list_num) ||
+		    !wpa_dbus_dict_end_array(&dict_iter,
 					     &iter_dict_entry,
 					     &iter_dict_val,
-					     &iter_dict_array))
-			goto err;
-
-		if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+					     &iter_dict_array) ||
+		    !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
 						res->persistent_group) ||
 		    !wpa_dbus_dict_append_uint32(&dict_iter,
 						 "peer_config_timeout",
@@ -1471,23 +1395,16 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
-		goto nomem;
-	if (bssid) {
-		if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
-						     (const char *) bssid,
-						     ETH_ALEN))
-			goto nomem;
-	}
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
+	    (bssid &&
+	     !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+					      (const char *) bssid,
+					      ETH_ALEN)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1537,18 +1454,12 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-
-	wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
-
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &path)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1598,19 +1509,13 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-
-	wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
-
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
-			      "signal");
+					    &path)) {
+		wpa_printf(MSG_ERROR,
+			   "dbus: Failed to construct PeerDisconnected signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1637,6 +1542,7 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
@@ -1646,16 +1552,16 @@
 	if (wpa_s->p2p_mgmt)
 		wpa_s = wpa_s->parent;
 
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
+		return;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "ServiceDiscoveryRequest");
 	if (msg == NULL)
 		return;
 
-	/* Check if this is a known peer */
-	if (!p2p_peer_known(wpa_s->global->p2p, sa))
-		goto error;
-
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
 		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1663,11 +1569,8 @@
 	path = peer_obj_path;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto error;
-
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
@@ -1678,13 +1581,9 @@
 					     (const char *) tlvs,
 					     tlvs_len) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto error;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-error:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1709,6 +1608,7 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
@@ -1718,16 +1618,16 @@
 	if (wpa_s->p2p_mgmt)
 		wpa_s = wpa_s->parent;
 
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
+		return;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "ServiceDiscoveryResponse");
 	if (msg == NULL)
 		return;
 
-	/* Check if this is a known peer */
-	if (!p2p_peer_known(wpa_s->global->p2p, sa))
-		goto error;
-
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
 		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1735,10 +1635,8 @@
 	path = peer_obj_path;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto error;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
 					 update_indic) ||
@@ -1746,17 +1644,13 @@
 					     (const char *) tlvs,
 					     tlvs_len) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto error;
-
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-error:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
+
 /**
  * wpas_dbus_signal_persistent_group - Send a persistent group related
  *	event signal
@@ -1798,23 +1692,15 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = pgrp_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
+					    &path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, pgrp_obj_path,
+		     WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, pgrp_obj_path,
-			    WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
 	dbus_message_unref(msg);
 }
 
@@ -1897,7 +1783,7 @@
 	dbus_message_unref(msg);
 }
 
-#endif /*CONFIG_P2P*/
+#endif /* CONFIG_P2P */
 
 
 /**
@@ -2091,7 +1977,7 @@
 
 static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
 	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2099,14 +1985,14 @@
 	  }
 	},
 	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
 	  {
 		  { "ifname", "s", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2164,14 +2050,6 @@
 		  END_ARGS
 	  }
 	},
-	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  { "field", "s", ARG_OUT },
-		  { "text", "s", ARG_OUT },
-		  END_ARGS
-	  }
-	},
 	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
 	  {
@@ -2198,8 +2076,8 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		return -1;
 	}
 
@@ -2313,16 +2191,16 @@
 		   net_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct network_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for method");
 		goto err;
 	}
 
@@ -2528,15 +2406,15 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	arg = os_zalloc(sizeof(struct bss_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for handler");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for handler");
 		goto err;
 	}
 	arg->wpa_s = wpa_s;
@@ -2569,27 +2447,27 @@
 
 static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
 	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+	  (WPADBusMethodHandler) wpas_dbus_handler_scan,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_signal_poll,
+	  (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
 	  {
 		  { "args", "a{sv}", ARG_OUT },
 		  END_ARGS
 	  }
 	},
 	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_network,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2597,39 +2475,39 @@
 	  }
 	},
 	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+	  (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_reattach,
+	  (WPADBusMethodHandler) wpas_dbus_handler_reattach,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_select_network,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+	  (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
 	  {
 		  { "path", "o", ARG_IN },
 		  { "field", "s", ARG_IN },
@@ -2639,7 +2517,7 @@
 	},
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  { "data", "ay", ARG_IN },
@@ -2647,7 +2525,7 @@
 	  }
 	},
 	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  { "data", "ay", ARG_OUT },
@@ -2655,7 +2533,7 @@
 	  }
 	},
 	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  END_ARGS
@@ -2664,7 +2542,7 @@
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 	{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler)
-	  &wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+	  wpas_dbus_handler_set_pkcs11_engine_and_module_path,
 	  {
 		  { "pkcs11_engine_path", "s", ARG_IN },
 		  { "pkcs11_module_path", "s", ARG_IN },
@@ -2673,7 +2551,7 @@
 	},
 #ifdef CONFIG_WPS
 	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+	  (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "output", "a{sv}", ARG_OUT },
@@ -2683,41 +2561,41 @@
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
 	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
 	  {
 		  { "timeout", "i", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
 	  {
 		  { "peer", "o", ARG_IN },
 		  { "config_method", "s", ARG_IN },
@@ -2725,7 +2603,7 @@
 	  }
 	},
 	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "generated_pin", "s", ARG_OUT },
@@ -2733,60 +2611,60 @@
 	  }
 	},
 	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
 	  {
 		  { "peer", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "ref", "t", ARG_OUT },
@@ -2794,27 +2672,27 @@
 	  }
 	},
 	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
 	  {
 		  { "args", "t", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
 	  {
 		  { "arg", "i", ARG_IN },
 		  END_ARGS
@@ -2844,7 +2722,7 @@
 	},
 #endif /* CONFIG_P2P */
 	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+	  (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
 	  {
 		  { "age", "u", ARG_IN },
 		  END_ARGS
@@ -2865,20 +2743,20 @@
 	},
 #endif /* CONFIG_AP */
 	{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
 	  {
 		  END_ARGS
 	  }
 	},
 #ifdef CONFIG_AUTOSCAN
 	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+	  (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
 	  {
 		  { "arg", "s", ARG_IN },
 		  END_ARGS
@@ -3124,12 +3002,6 @@
 	},
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
-	{ "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  {
-		  { "states", "a{ss}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
 	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 	  {
 		  { "path", "o", ARG_OUT },
@@ -3290,6 +3162,14 @@
 		  END_ARGS
 	  }
 	},
+	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "field", "s", ARG_OUT },
+		  { "text", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
 	{ NULL, NULL, { END_ARGS } }
 };
 
@@ -3316,8 +3196,8 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3352,7 +3232,7 @@
 	if (wpa_s == NULL || wpa_s->global == NULL)
 		return 0;
 	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
+	if (ctrl_iface == NULL || wpa_s->dbus_new_path == NULL)
 		return 0;
 
 	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
@@ -3481,15 +3361,10 @@
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
 					    &path))
-		goto err;
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
 	dbus_message_unref(msg);
 }
 
@@ -3558,16 +3433,16 @@
 		   peer_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct peer_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for method");
 		goto err;
 	}
 
@@ -3742,8 +3617,8 @@
 		   group_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3862,8 +3737,8 @@
 		   pgrp_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
-			   "object description");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3874,8 +3749,8 @@
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct network_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
-			   "arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to create arguments for method");
 		goto err;
 	}
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 5f32bbf..d162d2b 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -215,6 +215,8 @@
 				     struct wps_event_fail *fail);
 void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
 				    int depth, const char *subject,
+				    const char *altsubject[],
+				    int num_altsubject,
 				    const char *cert_hash,
 				    const struct wpabuf *cert);
 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
@@ -484,6 +486,8 @@
 static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
 						  int depth,
 						  const char *subject,
+						  const char *altsubject[],
+						  int num_altsubject,
 						  const char *cert_hash,
 						  const struct wpabuf *cert)
 {
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d6933cd..d695d1b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2,7 +2,7 @@
  * WPA Supplicant / dbus-based control interface
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,13 +29,13 @@
 #include "dbus_common_i.h"
 #include "drivers/driver.h"
 
-static const char *debug_strings[] = {
+static const char * const debug_strings[] = {
 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
 };
 
 
 /**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * wpas_dbus_error_unknown_error - Return a new UnknownError error message
  * @message: Pointer to incoming dbus message this error refers to
  * @arg: Optional string appended to error message
  * Returns: a dbus error message
@@ -45,20 +45,6 @@
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
 					    const char *arg)
 {
-	/*
-	 * This function can be called as a result of a failure
-	 * within internal getter calls, which will call this function
-	 * with a NULL message parameter.  However, dbus_message_new_error
-	 * looks very unkindly (i.e, abort()) on a NULL message, so
-	 * in this case, we should not call it.
-	 */
-	if (message == NULL) {
-		wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
-			   "called with NULL message (arg=%s)",
-			   arg ? arg : "N/A");
-		return NULL;
-	}
-
 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
 				      arg);
 }
@@ -73,9 +59,9 @@
  */
 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+		"wpa_supplicant knows nothing about this interface.");
 }
 
 
@@ -88,9 +74,9 @@
  */
 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
-				      "There is no such a network in this "
-				      "interface.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+		"There is no such a network in this interface.");
 }
 
 
@@ -106,9 +92,9 @@
 {
 	DBusMessage *reply;
 
-	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
-				       "Did not receive correct message "
-				       "arguments.");
+	reply = dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_INVALID_ARGS,
+		"Did not receive correct message arguments.");
 	if (arg != NULL)
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
 					 DBUS_TYPE_INVALID);
@@ -125,20 +111,23 @@
  *
  * Convenience function to create and return a scan error
  */
-DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
-					 const char *error)
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+						const char *error)
 {
-	DBusMessage *reply;
-
-	reply = dbus_message_new_error(message,
-				       WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
-				       error);
-
-	return reply;
+	return dbus_message_new_error(message,
+				      WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+				      error);
 }
 
 
-static const char *dont_quote[] = {
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
+{
+	wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+
+static const char * const dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
 	"bssid", "scan_freq", "freq_list", NULL
@@ -147,6 +136,7 @@
 static dbus_bool_t should_quote_opt(const char *key)
 {
 	int i = 0;
+
 	while (dont_quote[i] != NULL) {
 		if (os_strcmp(key, dont_quote[i]) == 0)
 			return FALSE;
@@ -264,6 +254,19 @@
 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
 			goto error;
 
+		if (os_strcmp(entry.key, "bssid") != 0 &&
+		    os_strcmp(entry.key, "priority") != 0)
+			wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+		if (wpa_s->current_ssid == ssid ||
+		    wpa_s->current_ssid == NULL) {
+			/*
+			 * Invalidate the EAP session cache if anything in the
+			 * current or previously used configuration changes.
+			 */
+			eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		}
+
 		if ((os_strcmp(entry.key, "psk") == 0 &&
 		     value[0] == '"' && ssid->ssid_len) ||
 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
@@ -306,27 +309,21 @@
 
 	if (!dbus_type_is_basic(type)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: given type is not basic", __func__);
+			       "%s: given type is not basic", __func__);
 		return FALSE;
 	}
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-	                                      wpa_dbus_type_as_string(type),
-	                                      &variant_iter))
-		goto error;
-
-	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
-		goto error;
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
-		goto error;
+					      wpa_dbus_type_as_string(type),
+					      &variant_iter) ||
+	    !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: error constructing reply", __func__);
+		return FALSE;
+	}
 
 	return TRUE;
-
-error:
-	dbus_set_error(error, DBUS_ERROR_FAILED,
-	               "%s: error constructing reply", __func__);
-	return FALSE;
 }
 
 
@@ -389,7 +386,7 @@
 
 	if (!dbus_type_is_basic(type)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: given type is not basic", __func__);
+			       "%s: given type is not basic", __func__);
 		return FALSE;
 	}
 
@@ -397,20 +394,15 @@
 	type_str[1] = sub_type_str[0];
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      type_str, &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      sub_type_str, &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message", __func__);
 		return FALSE;
 	}
 
-	switch(type) {
+	switch (type) {
 	case DBUS_TYPE_BYTE:
 	case DBUS_TYPE_BOOLEAN:
 		element_size = 1;
@@ -436,7 +428,7 @@
 		break;
 	default:
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: unknown element type %d", __func__, type);
+			       "%s: unknown element type %d", __func__, type);
 		return FALSE;
 	}
 
@@ -450,15 +442,10 @@
 		}
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 3", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 4", __func__);
+			       "%s: failed to construct message 3", __func__);
 		return FALSE;
 	}
 
@@ -501,15 +488,11 @@
 	inner_type_str[1] = sub_type_str[0];
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      type_str, &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      inner_type_str, &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message", __func__);
 		return FALSE;
 	}
 
@@ -520,15 +503,10 @@
 
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to close message 2", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to close message 1", __func__);
+			       "%s: failed to close message", __func__);
 		return FALSE;
 	}
 
@@ -566,34 +544,34 @@
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
-		if (!os_strcmp(entry.key, "Driver") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
+		if (os_strcmp(entry.key, "Driver") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
 			os_free(driver);
 			driver = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (driver == NULL)
-				goto error;
-		} else if (!os_strcmp(entry.key, "Ifname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+				goto oom;
+		} else if (os_strcmp(entry.key, "Ifname") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(ifname);
 			ifname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (ifname == NULL)
-				goto error;
-		} else if (!os_strcmp(entry.key, "ConfigFile") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+				goto oom;
+		} else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(confname);
 			confname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (confname == NULL)
-				goto error;
-		} else if (!os_strcmp(entry.key, "BridgeIfname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+				goto oom;
+		} else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(bridge_ifname);
 			bridge_ifname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (bridge_ifname == NULL)
-				goto error;
+				goto oom;
 		} else {
 			wpa_dbus_dict_entry_clear(&entry);
 			goto error;
@@ -608,28 +586,30 @@
 	 * an error if we already control it.
 	 */
 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_DBUS_ERROR_IFACE_EXISTS,
-					       "wpa_supplicant already "
-					       "controls this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_DBUS_ERROR_IFACE_EXISTS,
+			"wpa_supplicant already controls this interface.");
 	} else {
 		struct wpa_supplicant *wpa_s;
 		struct wpa_interface iface;
+
 		os_memset(&iface, 0, sizeof(iface));
 		iface.driver = driver;
 		iface.ifname = ifname;
 		iface.confname = confname;
 		iface.bridge_ifname = bridge_ifname;
 		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+		if (wpa_s) {
 			const char *path = wpa_s->dbus_new_path;
+
 			reply = dbus_message_new_method_return(message);
 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
+						 &path, DBUS_TYPE_INVALID);
 		} else {
 			reply = wpas_dbus_error_unknown_error(
-				message, "wpa_supplicant couldn't grab this "
-				"interface.");
+				message,
+				"wpa_supplicant couldn't grab this interface.");
 		}
 	}
 
@@ -643,6 +623,9 @@
 error:
 	reply = wpas_dbus_error_invalid_args(message, NULL);
 	goto out;
+oom:
+	reply = wpas_dbus_error_no_memory(message);
+	goto out;
 }
 
 
@@ -672,8 +655,8 @@
 		reply = wpas_dbus_error_iface_unknown(message);
 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
 		reply = wpas_dbus_error_unknown_error(
-			message, "wpa_supplicant couldn't remove this "
-			"interface.");
+			message,
+			"wpa_supplicant couldn't remove this interface.");
 	}
 
 	return reply;
@@ -707,13 +690,11 @@
 	path = wpa_s->dbus_new_path;
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -756,8 +737,8 @@
  * Getter for "DebugTimestamp" property.
  */
 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data)
+					     DBusError *error,
+					     void *user_data)
 {
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
 						&wpa_debug_timestamp, error);
@@ -812,8 +793,8 @@
 	if (val < 0 ||
 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
 					    wpa_debug_show_keys)) {
-		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
-				     "level value");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "wrong debug level value");
 		return FALSE;
 	}
 
@@ -963,8 +944,8 @@
  * and P2P that are determined at compile time.
  */
 dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
-					         DBusError *error,
-					         void *user_data)
+						 DBusError *error,
+						 void *user_data)
 {
 	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
 	size_t num_items = 0;
@@ -993,8 +974,8 @@
 				   char **type, DBusMessage **reply)
 {
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Type must be a string");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong Type value type. String required");
 		return -1;
@@ -1016,36 +997,36 @@
 	int len;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ssids must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong SSIDs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
 	dbus_message_iter_recurse(var, &array_iter);
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ssids must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong SSIDs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Too many ssids specified on scan dbus "
-				   "call");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Too many ssids specified on scan dbus call",
+				   __func__);
 			*reply = wpas_dbus_error_invalid_args(
-				message, "Too many ssids specified. Specify "
-				"at most four");
+				message,
+				"Too many ssids specified. Specify at most four");
 			return -1;
 		}
 
@@ -1053,11 +1034,10 @@
 
 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
 
-		if (len > MAX_SSID_LEN) {
+		if (len > SSID_MAX_LEN) {
 			wpa_printf(MSG_DEBUG,
-				   "wpas_dbus_handler_scan[dbus]: "
-				   "SSID too long (len=%d max_len=%d)",
-				   len, MAX_SSID_LEN);
+				   "%s[dbus]: SSID too long (len=%d max_len=%d)",
+				   __func__, len, SSID_MAX_LEN);
 			*reply = wpas_dbus_error_invalid_args(
 				message, "Invalid SSID: too long");
 			return -1;
@@ -1066,12 +1046,7 @@
 		if (len != 0) {
 			ssid = os_malloc(len);
 			if (ssid == NULL) {
-				wpa_printf(MSG_DEBUG,
-					   "wpas_dbus_handler_scan[dbus]: "
-					   "out of memory. Cannot allocate "
-					   "memory for SSID");
-				*reply = dbus_message_new_error(
-					message, DBUS_ERROR_NO_MEMORY, NULL);
+				*reply = wpas_dbus_error_no_memory(message);
 				return -1;
 			}
 			os_memcpy(ssid, val, len);
@@ -1103,28 +1078,28 @@
 	int len;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ies must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong IEs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong IEs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
 	dbus_message_iter_recurse(var, &array_iter);
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ies must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong IEs value type. Array required");
 		return -1;
 	}
 
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
 
 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
@@ -1135,12 +1110,8 @@
 
 		nies = os_realloc(ies, ies_len + len);
 		if (nies == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. Cannot allocate memory for "
-				   "IE");
 			os_free(ies);
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
+			*reply = wpas_dbus_error_no_memory(message);
 			return -1;
 		}
 		ies = nies;
@@ -1166,11 +1137,12 @@
 	int freqs_num = 0;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Channels must be an array of structs");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: Channels must be an array of structs",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
+			message,
+			"Wrong Channels value type. Array of structs required");
 		return -1;
 	}
 
@@ -1178,11 +1150,11 @@
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
 		wpa_printf(MSG_DEBUG,
-			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
-			   "array of structs");
+			   "%s[dbus]: Channels must be an array of structs",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
+			message,
+			"Wrong Channels value type. Array of structs required");
 		return -1;
 	}
 
@@ -1194,14 +1166,14 @@
 
 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
 		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s %c",
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
+				   __func__,
 				   dbus_message_iter_get_arg_type(
 					   &sub_array_iter));
 			*reply = wpas_dbus_error_invalid_args(
-				message, "Wrong Channel struct. Two UINT32s "
-				"required");
+				message,
+				"Wrong Channel struct. Two UINT32s required");
 			os_free(freqs);
 			return -1;
 		}
@@ -1210,9 +1182,9 @@
 		if (!dbus_message_iter_next(&sub_array_iter) ||
 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
 		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Channel must by specified by struct of two UINT32s",
+				   __func__);
 			*reply = wpas_dbus_error_invalid_args(
 				message,
 				"Wrong Channel struct. Two UINT32s required");
@@ -1232,11 +1204,7 @@
 			freqs = nfreqs;
 		}
 		if (freqs == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. can't allocate memory for "
-				   "freqs");
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
+			*reply = wpas_dbus_error_no_memory(message);
 			return -1;
 		}
 
@@ -1251,10 +1219,7 @@
 		os_free(freqs);
 	freqs = nfreqs;
 	if (freqs == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "out of memory. Can't allocate memory for freqs");
-		*reply = dbus_message_new_error(
-			message, DBUS_ERROR_NO_MEMORY, NULL);
+		*reply = wpas_dbus_error_no_memory(message);
 		return -1;
 	}
 	freqs[freqs_num] = 0;
@@ -1270,8 +1235,8 @@
 					 DBusMessage **reply)
 {
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Type must be a boolean");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong Type value type. Boolean required");
 		return -1;
@@ -1308,7 +1273,7 @@
 	dbus_message_iter_recurse(&iter, &dict_iter);
 
 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
-			DBUS_TYPE_DICT_ENTRY) {
+	       DBUS_TYPE_DICT_ENTRY) {
 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
 		dbus_message_iter_get_basic(&entry_iter, &key);
 		dbus_message_iter_next(&entry_iter);
@@ -1337,8 +1302,8 @@
 							  &reply) < 0)
 				goto out;
 		} else {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Unknown argument %s", key);
+			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
+				   __func__, key);
 			reply = wpas_dbus_error_invalid_args(message, key);
 			goto out;
 		}
@@ -1347,19 +1312,20 @@
 	}
 
 	if (!type) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Scan type not specified");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
+			   __func__);
 		reply = wpas_dbus_error_invalid_args(message, key);
 		goto out;
 	}
 
-	if (!os_strcmp(type, "passive")) {
+	if (os_strcmp(type, "passive") == 0) {
 		if (params.num_ssids || params.extra_ies_len) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "SSIDs or IEs specified for passive scan.");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
+				   __func__);
 			reply = wpas_dbus_error_invalid_args(
-				message, "You can specify only Channels in "
-				"passive scan");
+				message,
+				"You can specify only Channels in passive scan");
 			goto out;
 		} else if (params.freqs && params.freqs[0]) {
 			if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
@@ -1370,7 +1336,7 @@
 			wpa_s->scan_req = MANUAL_SCAN_REQ;
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
-	} else if (!os_strcmp(type, "active")) {
+	} else if (os_strcmp(type, "active") == 0) {
 		if (!params.num_ssids) {
 			/* Add wildcard ssid */
 			params.num_ssids++;
@@ -1383,8 +1349,8 @@
 				message, "Scan request rejected");
 		}
 	} else {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Unknown scan type: %s", type);
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
+			   __func__, type);
 		reply = wpas_dbus_error_invalid_args(message,
 						     "Wrong scan type");
 		goto out;
@@ -1433,45 +1399,30 @@
 	dbus_message_iter_init_append(reply, &iter);
 
 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "rssi", si.current_signal))
-		goto nomem;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
-					si.current_txrate / 1000))
-		goto nomem;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", si.current_noise))
-		goto nomem;
-	if (!wpa_dbus_dict_append_uint32(&iter_dict, "frequency", si.frequency))
-		goto nomem;
-
-	if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
-		if (!wpa_dbus_dict_append_string(&iter_dict, "width",
-					channel_width_to_string(si.chanwidth)))
-			goto nomem;
-	}
-
-	if (si.center_frq1 > 0 && si.center_frq2 > 0) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
-						si.center_frq1))
-			goto nomem;
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
-						si.center_frq2))
-			goto nomem;
-	}
-
-	if (si.avg_signal) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
-						si.avg_signal))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+					si.current_signal) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+					si.current_txrate / 1000) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+					si.current_noise) ||
+	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+					 si.frequency) ||
+	    (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+	     !wpa_dbus_dict_append_string(
+		     &iter_dict, "width",
+		     channel_width_to_string(si.chanwidth))) ||
+	    (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+					  si.center_frq1) ||
+	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+					  si.center_frq2))) ||
+	    (si.avg_signal &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+					 si.avg_signal)) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(&iter, &variant_iter))
 		goto nomem;
 
 	return reply;
@@ -1479,8 +1430,7 @@
 nomem:
 	if (reply)
 		dbus_message_unref(reply);
-	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
-	return reply;
+	return wpas_dbus_error_no_memory(message);
 }
 
 
@@ -1530,12 +1480,11 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
-			   "can't add new interface.");
+		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+			   __func__);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"wpa_supplicant could not add "
-			"a network on this interface.");
+			"wpa_supplicant could not add a network on this interface.");
 		goto err;
 	}
 	wpas_notify_network_added(wpa_s, ssid);
@@ -1544,9 +1493,9 @@
 
 	dbus_error_init(&error);
 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
-			   "control interface couldn't set network "
-			   "properties");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: control interface couldn't set network properties",
+			   __func__);
 		reply = wpas_dbus_reply_new_from_error(message, &error,
 						       DBUS_ERROR_INVALID_ARGS,
 						       "Failed to add network");
@@ -1561,15 +1510,13 @@
 
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
@@ -1642,7 +1589,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 	int was_disabled;
@@ -1652,7 +1599,9 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1680,25 +1629,24 @@
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	else if (!was_disabled && wpa_s->sched_scanning) {
-		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
-			   "network from filters");
+		wpa_printf(MSG_DEBUG,
+			   "Stop ongoing sched_scan to remove network from filters");
 		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
 
 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
 		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_handler_remove_network[dbus]: "
-			   "error occurred when removing network %d", id);
+			   "%s[dbus]: error occurred when removing network %d",
+			   __func__, id);
 		reply = wpas_dbus_error_unknown_error(
-			message, "error removing the specified network on "
-			"this interface.");
+			message,
+			"error removing the specified network on is interface.");
 		goto out;
 	}
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 }
 
@@ -1711,9 +1659,8 @@
 
 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
 		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_handler_remove_all_networks[dbus]: "
-			   "error occurred when removing network %d",
-			   ssid->id);
+			   "%s[dbus]: error occurred when removing network %d",
+			   __func__, ssid->id);
 		return;
 	}
 
@@ -1756,7 +1703,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 
@@ -1765,7 +1712,9 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1790,7 +1739,6 @@
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 }
 
@@ -1809,20 +1757,22 @@
 #ifdef IEEE8021X_EAPOL
 	DBusMessage *reply = NULL;
 	const char *op, *field, *value;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_OBJECT_PATH, &op,
-	                           DBUS_TYPE_STRING, &field,
-	                           DBUS_TYPE_STRING, &value,
-			           DBUS_TYPE_INVALID))
+				   DBUS_TYPE_OBJECT_PATH, &op,
+				   DBUS_TYPE_STRING, &field,
+				   DBUS_TYPE_STRING, &value,
+				   DBUS_TYPE_INVALID))
 		return wpas_dbus_error_invalid_args(message, NULL);
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1852,7 +1802,6 @@
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 #else /* IEEE8021X_EAPOL */
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
@@ -1898,26 +1847,18 @@
 
 	blob = os_zalloc(sizeof(*blob));
 	if (!blob) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
 	blob->data = os_malloc(blob_len);
-	if (!blob->data) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+	blob->name = os_strdup(blob_name);
+	if (!blob->data || !blob->name) {
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	os_memcpy(blob->data, blob_data, blob_len);
-
 	blob->len = blob_len;
-	blob->name = os_strdup(blob_name);
-	if (!blob->name) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
 
 	wpa_config_set_blob(wpa_s->conf, blob);
 	wpas_notify_blob_added(wpa_s, blob->name);
@@ -1962,39 +1903,21 @@
 	}
 
 	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
+	if (!reply)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
 
 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &array_iter)) {
+					      &array_iter) ||
+	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+						  &(blob->data), blob->len) ||
+	    !dbus_message_iter_close_container(&iter, &array_iter)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
+		reply = wpas_dbus_error_no_memory(message);
 	}
 
-	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
-						  &(blob->data), blob->len)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-out:
 	return reply;
 }
 
@@ -2076,11 +1999,10 @@
 
 	if (arg != NULL && os_strlen(arg) > 0) {
 		char *tmp;
+
 		tmp = os_strdup(arg);
 		if (tmp == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			reply = wpas_dbus_error_no_memory(message);
 		} else {
 			os_free(wpa_s->conf->autoscan);
 			wpa_s->conf->autoscan = tmp;
@@ -2342,8 +2264,7 @@
 						   pkcs11_module_path))
 		return dbus_message_new_error(
 			message, DBUS_ERROR_FAILED,
-			"Reinit of the EAPOL state machine with the new PKCS "
-			"#11 engine and module path failed.");
+			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
 
 	wpa_dbus_mark_property_changed(
 		wpa_s->global->dbus, wpa_s->dbus_new_path,
@@ -2376,10 +2297,8 @@
 	const char *scans[] = { "active", "passive", "ssid" };
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
 		goto nomem;
 
 	res = wpa_drv_get_capa(wpa_s, &capa);
@@ -2387,6 +2306,7 @@
 	/***** pairwise cipher */
 	if (res < 0) {
 		const char *args[] = {"ccmp", "tkip", "none"};
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Pairwise", args,
 			    ARRAY_SIZE(args)))
@@ -2395,46 +2315,26 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "none"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "tkip")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "none")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2446,6 +2346,7 @@
 		const char *args[] = {
 			"ccmp", "tkip", "wep104", "wep40"
 		};
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Group", args,
 			    ARRAY_SIZE(args)))
@@ -2454,52 +2355,29 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep104"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep40"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "tkip")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wep104")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wep40")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2523,28 +2401,22 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "none"))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+						      &iter_array) ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "none") ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
 							    "ieee8021x"))
 			goto nomem;
 
 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
 			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-eap"))
+				    &iter_array, "wpa-eap") ||
+			    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+			     !wpa_dbus_dict_string_array_add_element(
+				     &iter_array, "wpa-ft-eap")))
 				goto nomem;
 
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-eap"))
-					goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
 			if (!wpa_dbus_dict_string_array_add_element(
@@ -2556,14 +2428,13 @@
 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-psk"))
+				    &iter_array, "wpa-psk") ||
+			    ((capa.key_mgmt &
+			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+			     !wpa_dbus_dict_string_array_add_element(
+				     &iter_array, "wpa-ft-psk")))
 				goto nomem;
 
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-psk"))
-					goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
 			if (!wpa_dbus_dict_string_array_add_element(
@@ -2572,11 +2443,10 @@
 #endif /* CONFIG_IEEE80211W */
 		}
 
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-none"))
-				goto nomem;
-		}
+		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "wpa-none"))
+			goto nomem;
 
 
 #ifdef CONFIG_WPS
@@ -2595,6 +2465,7 @@
 	/***** WPA protocol */
 	if (res < 0) {
 		const char *args[] = { "rsn", "wpa" };
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Protocol", args,
 			    ARRAY_SIZE(args)))
@@ -2603,24 +2474,16 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "rsn"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "rsn")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wpa")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2630,6 +2493,7 @@
 	/***** auth alg */
 	if (res < 0) {
 		const char *args[] = { "open", "shared", "leap" };
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "AuthAlg", args,
 			    ARRAY_SIZE(args)))
@@ -2641,25 +2505,16 @@
 						      &iter_array))
 			goto nomem;
 
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "open"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "shared"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "leap"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "open")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "shared")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "leap")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2675,32 +2530,18 @@
 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
 					      &iter_dict_entry,
 					      &iter_dict_val,
-					      &iter_array))
-		goto nomem;
-
-	if (!wpa_dbus_dict_string_array_add_element(
-			    &iter_array, "infrastructure"))
-		goto nomem;
-
-	if (!wpa_dbus_dict_string_array_add_element(
-			    &iter_array, "ad-hoc"))
-		goto nomem;
-
-	if (res >= 0) {
-		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ap"))
-				goto nomem;
-		}
-
-		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "p2p"))
-				goto nomem;
-		}
-	}
-
-	if (!wpa_dbus_dict_end_string_array(&iter_dict,
+					      &iter_array) ||
+	    !wpa_dbus_dict_string_array_add_element(
+		    &iter_array, "infrastructure") ||
+	    !wpa_dbus_dict_string_array_add_element(
+		    &iter_array, "ad-hoc") ||
+	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "ap")) ||
+	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "p2p")) ||
+	    !wpa_dbus_dict_end_string_array(&iter_dict,
 					    &iter_dict_entry,
 					    &iter_dict_val,
 					    &iter_array))
@@ -2715,9 +2556,8 @@
 			goto nomem;
 	}
 
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -2778,7 +2618,7 @@
  * Getter for "scanning" property.
  */
 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data)
+				      void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2900,6 +2740,7 @@
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	dbus_int32_t reason = wpa_s->disconnect_reason;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
 						&reason, error);
 }
@@ -3154,8 +2995,8 @@
 	const char *driver;
 
 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
-			   "wpa_s has no driver set");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
+			   __func__);
 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
 			       __func__);
 		return FALSE;
@@ -3275,6 +3116,7 @@
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *bridge_ifname = wpa_s->bridge_ifname;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
 						&bridge_ifname, error);
 }
@@ -3349,14 +3191,6 @@
 	unsigned int i = 0, num = 0;
 	dbus_bool_t success = FALSE;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
-			   "networks list.", __func__);
-		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
-			       "occurred getting the networks list", __func__);
-		return FALSE;
-	}
-
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
 		if (!network_is_persistent_group(ssid))
 			num++;
@@ -3373,7 +3207,8 @@
 			continue;
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
-			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
+				       "no memory");
 			goto out;
 		}
 
@@ -3411,16 +3246,6 @@
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *pkcs11_engine_path;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
-			   "error occurred getting the PKCS #11 engine path.");
-		dbus_set_error_const(
-			error, DBUS_ERROR_FAILED,
-			"An error occured getting the PKCS #11 engine path.");
-		return FALSE;
-	}
-
 	if (wpa_s->conf->pkcs11_engine_path == NULL)
 		pkcs11_engine_path = "";
 	else
@@ -3446,16 +3271,6 @@
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *pkcs11_module_path;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
-			   "error occurred getting the PKCS #11 module path.");
-		dbus_set_error_const(
-			error, DBUS_ERROR_FAILED,
-			"An error occured getting the PKCS #11 module path.");
-		return FALSE;
-	}
-
 	if (wpa_s->conf->pkcs11_module_path == NULL)
 		pkcs11_module_path = "";
 	else
@@ -3534,7 +3349,7 @@
 
 	if (!res) {
 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
-		           func_name, args->id);
+			   func_name, args->id);
 		dbus_set_error(error, DBUS_ERROR_FAILED,
 			       "%s: BSS %d not found",
 			       func_name, args->id);
@@ -3775,7 +3590,7 @@
 	DBusMessageIter iter_dict, variant_iter;
 	const char *group;
 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
-	const char *key_mgmt[8]; /* max 8 key managements may be supported */
+	const char *key_mgmt[9]; /* max 9 key managements may be supported */
 	int n;
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3799,8 +3614,14 @@
 		key_mgmt[n++] = "wpa-ft-eap";
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
 		key_mgmt[n++] = "wpa-eap-sha256";
+#ifdef CONFIG_SUITEB
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
 		key_mgmt[n++] = "wpa-eap-suite-b";
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+		key_mgmt[n++] = "wpa-eap-suite-b-192";
+#endif /* CONFIG_SUITEB192 */
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
 		key_mgmt[n++] = "wpa-none";
 
@@ -3874,9 +3695,8 @@
 			goto nomem;
 	}
 
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -3910,12 +3730,10 @@
 
 	os_memset(&wpa_data, 0, sizeof(wpa_data));
 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-			dbus_set_error_const(error, DBUS_ERROR_FAILED,
-					     "failed to parse WPA IE");
-			return FALSE;
-		}
+	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to parse WPA IE");
+		return FALSE;
 	}
 
 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3945,12 +3763,10 @@
 
 	os_memset(&wpa_data, 0, sizeof(wpa_data));
 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-			dbus_set_error_const(error, DBUS_ERROR_FAILED,
-					     "failed to parse RSN IE");
-			return FALSE;
-		}
+	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to parse RSN IE");
+		return FALSE;
 	}
 
 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3975,6 +3791,7 @@
 	struct wpabuf *wps_ie;
 #endif /* CONFIG_WPS */
 	DBusMessageIter iter_dict, variant_iter;
+	int wps_support = 0;
 	const char *type = "";
 
 	res = get_bss_helper(args, error, __func__);
@@ -3982,15 +3799,14 @@
 		return FALSE;
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
 		goto nomem;
 
 #ifdef CONFIG_WPS
 	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
 	if (wps_ie) {
+		wps_support = 1;
 		if (wps_is_selected_pbc_registrar(wps_ie))
 			type = "pbc";
 		else if (wps_is_selected_pin_registrar(wps_ie))
@@ -4000,12 +3816,9 @@
 	}
 #endif /* CONFIG_WPS */
 
-	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
-		goto nomem;
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -4227,8 +4040,7 @@
 
 	name = os_strdup(dbus_message_get_sender(message));
 	if (!name)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      "out of memory");
+		return wpas_dbus_error_no_memory(message);
 
 	wpa_s->preq_notify_peer = name;
 
@@ -4308,28 +4120,22 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto fail;
-	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
-						     (const char *) addr,
-						     ETH_ALEN))
-		goto fail;
-	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
-						    (const char *) dst,
-						    ETH_ALEN))
-		goto fail;
-	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
-						      (const char *) bssid,
-						      ETH_ALEN))
-		goto fail;
-	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
-							     (const char *) ie,
-							     ie_len))
-		goto fail;
-	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
-						      ssi_signal))
-		goto fail;
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+						      (const char *) addr,
+						      ETH_ALEN)) ||
+	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+						     (const char *) dst,
+						     ETH_ALEN)) ||
+	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+						       (const char *) bssid,
+						       ETH_ALEN)) ||
+	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+							      (const char *) ie,
+							      ie_len)) ||
+	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+						       ssi_signal)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
 		goto fail;
 
 	dbus_connection_send(priv->con, msg, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index f6a83cd..6113db5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -55,8 +55,8 @@
 					 void *user_data);
 
 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data);
+					     DBusError *error,
+					     void *user_data);
 
 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
 					     DBusError *error,
@@ -319,6 +319,7 @@
 					   const char *arg);
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
 					    const char *arg);
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message);
 
 DBusMessage * wpas_dbus_handler_subscribe_preq(
 	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 f006887..0eff763 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -35,9 +35,9 @@
  * @addr - out param must be of ETH_ALEN size
  * Returns 0 if valid (including MAC), -1 otherwise
  */
-static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
 {
-	char *p;
+	const char *p;
 
 	if (!peer_path)
 		return -1;
@@ -57,12 +57,12 @@
  *
  * Convenience function to create and return an invalid persistent group error.
  */
-static DBusMessage * wpas_dbus_error_persistent_group_unknown(
-	DBusMessage *message)
+static DBusMessage *
+wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
-				      "There is no such persistent group in "
-				      "this P2P device.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+		"There is no such persistent group in this P2P device.");
 }
 
 
@@ -89,12 +89,12 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "Timeout") &&
-		    (entry.type == DBUS_TYPE_INT32)) {
+		if (os_strcmp(entry.key, "Timeout") == 0 &&
+		    entry.type == DBUS_TYPE_INT32) {
 			timeout = entry.uint32_value;
 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
 				goto error_clear;
 
 			os_free(req_dev_types);
@@ -105,20 +105,20 @@
 
 			for (i = 0; i < entry.array_len; i++) {
 				if (wpabuf_len(entry.binarray_value[i]) !=
-							WPS_DEV_TYPE_LEN)
+				    WPS_DEV_TYPE_LEN)
 					goto error_clear;
 				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
 					  wpabuf_head(entry.binarray_value[i]),
 					  WPS_DEV_TYPE_LEN);
 			}
 			num_req_dev_types = entry.array_len;
-		} else if (!os_strcmp(entry.key, "DiscoveryType") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "start_with_full"))
+		} else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "start_with_full") == 0)
 				type = P2P_FIND_START_WITH_FULL;
-			else if (!os_strcmp(entry.str_value, "social"))
+			else if (os_strcmp(entry.str_value, "social") == 0)
 				type = P2P_FIND_ONLY_SOCIAL;
-			else if (!os_strcmp(entry.str_value, "progressive"))
+			else if (os_strcmp(entry.str_value, "progressive") == 0)
 				type = P2P_FIND_PROGRESSIVE;
 			else
 				goto error_clear;
@@ -131,7 +131,7 @@
 		wpa_s = wpa_s->p2p_dev;
 
 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
-		      NULL, 0);
+		      NULL, 0, 0, NULL, 0);
 	os_free(req_dev_types);
 	return reply;
 
@@ -186,15 +186,16 @@
 
 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
 				   DBUS_TYPE_INVALID))
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 
 	if (wpa_s->p2p_dev)
 		wpa_s = wpa_s->p2p_dev;
 
-	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+					      "Could not start P2P listen");
+	}
 
 	return NULL;
 }
@@ -218,11 +219,11 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "period") &&
-		    (entry.type == DBUS_TYPE_INT32))
+		if (os_strcmp(entry.key, "period") == 0 &&
+		    entry.type == DBUS_TYPE_INT32)
 			period = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval") &&
-			 (entry.type == DBUS_TYPE_INT32))
+		else if (os_strcmp(entry.key, "interval") == 0 &&
+			 entry.type == DBUS_TYPE_INT32)
 			interval = entry.uint32_value;
 		else
 			goto error_clear;
@@ -263,16 +264,16 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "duration1") &&
-		    (entry.type == DBUS_TYPE_INT32))
+		if (os_strcmp(entry.key, "duration1") == 0 &&
+		    entry.type == DBUS_TYPE_INT32)
 			dur1 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval1") &&
+		else if (os_strcmp(entry.key, "interval1") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			int1 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "duration2") &&
+		else if (os_strcmp(entry.key, "duration2") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			dur2 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval2") &&
+		else if (os_strcmp(entry.key, "interval2") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			int2 = entry.uint32_value;
 		else
@@ -308,7 +309,6 @@
 	int persistent_group = 0;
 	int freq = 0;
 	char *iface = NULL;
-	char *net_id_str = NULL;
 	unsigned int group_id = 0;
 	struct wpa_ssid *ssid;
 
@@ -321,15 +321,16 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!os_strcmp(entry.key, "persistent") &&
-		    (entry.type == DBUS_TYPE_BOOLEAN)) {
-			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "frequency") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		if (os_strcmp(entry.key, "persistent") == 0 &&
+		    entry.type == DBUS_TYPE_BOOLEAN) {
+			persistent_group = entry.bool_value;
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
+		} else if (os_strcmp(entry.key, "persistent_group_object") ==
+			   0 &&
 			   entry.type == DBUS_TYPE_OBJECT_PATH)
 			pg_object_path = os_strdup(entry.str_value);
 		else
@@ -342,14 +343,17 @@
 		wpa_s = wpa_s->p2p_dev;
 
 	if (pg_object_path != NULL) {
+		char *net_id_str;
+
 		/*
 		 * A persistent group Object Path is defined meaning we want
 		 * to re-invoke a persistent group.
 		 */
 
-		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
-							    &net_id_str, NULL);
-		if (iface == NULL ||
+		iface = wpas_dbus_new_decompose_object_path(
+			pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+			&net_id_str);
+		if (iface == NULL || net_id_str == NULL ||
 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 			reply =
 			    wpas_dbus_error_invalid_args(message,
@@ -381,7 +385,6 @@
 
 out:
 	os_free(pg_object_path);
-	os_free(net_id_str);
 	os_free(iface);
 	return reply;
 inv_args_clear:
@@ -416,8 +419,7 @@
 				"P2P is not available for this interface");
 		}
 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
-				     "P2P is not available for this "
-				     "interface");
+				     "P2P is not available for this interface");
 		return FALSE;
 	}
 	return TRUE;
@@ -475,42 +477,42 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!os_strcmp(entry.key, "peer") &&
-		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		if (os_strcmp(entry.key, "peer") == 0 &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "persistent") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "join") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			join = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "authorize_only") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "frequency") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		} else if (os_strcmp(entry.key, "persistent") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			persistent_group = entry.bool_value;
+		} else if (os_strcmp(entry.key, "join") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			join = entry.bool_value;
+		} else if (os_strcmp(entry.key, "authorize_only") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			authorize_only = entry.bool_value;
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "go_intent") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		} else if (os_strcmp(entry.key, "go_intent") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			go_intent = entry.int32_value;
 			if ((go_intent < 0) || (go_intent > 15))
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "wps_method") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "pbc"))
+		} else if (os_strcmp(entry.key, "wps_method") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "pbc") == 0)
 				wps_method = WPS_PBC;
-			else if (!os_strcmp(entry.str_value, "pin"))
+			else if (os_strcmp(entry.str_value, "pin") == 0)
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!os_strcmp(entry.str_value, "display"))
+			else if (os_strcmp(entry.str_value, "display") == 0)
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!os_strcmp(entry.str_value, "keypad"))
+			else if (os_strcmp(entry.str_value, "keypad") == 0)
 				wps_method = WPS_PIN_KEYPAD;
 			else
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "pin") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "pin") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			pin = os_strdup(entry.str_value);
 		} else
 			goto inv_args_clear;
@@ -518,15 +520,15 @@
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
-	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
-	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	if (wps_method == WPS_NOT_READY ||
+	    parse_peer_object_path(peer_object_path, addr) < 0 ||
 	    !p2p_peer_known(wpa_s->global->p2p, addr))
 		goto inv_args;
 
 	/*
 	 * Validate the wps_method specified and the pin value.
 	 */
-	if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+	if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
 		goto inv_args;
 
 	if (wpa_s->p2p_dev)
@@ -539,6 +541,7 @@
 	if (new_pin >= 0) {
 		char npin[9];
 		char *generated_pin;
+
 		os_snprintf(npin, sizeof(npin), "%08d", new_pin);
 		generated_pin = npin;
 		reply = dbus_message_new_method_return(message);
@@ -547,8 +550,8 @@
 	} else {
 		switch (new_pin) {
 		case -2:
-			err_msg = "connect failed due to channel "
-				"unavailability.";
+			err_msg =
+				"connect failed due to channel unavailability.";
 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
 			break;
 
@@ -594,7 +597,6 @@
 	char *peer_object_path = NULL;
 	char *pg_object_path = NULL;
 	char *iface = NULL;
-	char *net_id_str = NULL;
 	u8 peer_addr[ETH_ALEN];
 	unsigned int group_id = 0;
 	int persistent = 0;
@@ -612,12 +614,13 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto err;
 
-		if (!os_strcmp(entry.key, "peer") &&
-		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		if (os_strcmp(entry.key, "peer") == 0 &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
-		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
-			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		} else if (os_strcmp(entry.key, "persistent_group_object") ==
+			   0 &&
+			   entry.type == DBUS_TYPE_OBJECT_PATH) {
 			pg_object_path = os_strdup(entry.str_value);
 			persistent = 1;
 			wpa_dbus_dict_entry_clear(&entry);
@@ -627,24 +630,25 @@
 		}
 	}
 
-	if (!peer_object_path ||
-	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
-	    !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+	    !p2p_peer_known(wpa_s->global->p2p, peer_addr))
 		goto err;
-	}
 
 	if (wpa_s->p2p_dev)
 		wpa_s = wpa_s->p2p_dev;
 
 	if (persistent) {
+		char *net_id_str;
 		/*
 		 * A group ID is defined meaning we want to re-invoke a
 		 * persistent group
 		 */
 
-		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
-							    &net_id_str, NULL);
-		if (iface == NULL ||
+		iface = wpas_dbus_new_decompose_object_path(
+			pg_object_path,
+			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+			&net_id_str);
+		if (iface == NULL || net_id_str == NULL ||
 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 			reply = wpas_dbus_error_invalid_args(message,
 							     pg_object_path);
@@ -683,6 +687,7 @@
 	}
 
 out:
+	os_free(iface);
 	os_free(pg_object_path);
 	os_free(peer_object_path);
 	return reply;
@@ -725,7 +730,7 @@
 		wpa_s = wpa_s->p2p_dev;
 
 	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
-			       WPAS_P2P_PD_FOR_GO_NEG) < 0)
+			       WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
 		return wpas_dbus_error_unknown_error(message,
 				"Failed to send provision discovery request");
 
@@ -769,8 +774,8 @@
 
 	/* Primary device type */
 	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
-	    				     (char *)wpa_s->conf->device_type,
-	    				     WPS_DEV_TYPE_LEN))
+					     (char *) wpa_s->conf->device_type,
+					     WPS_DEV_TYPE_LEN))
 		goto err_no_mem;
 
 	/* Secondary device types */
@@ -805,75 +810,37 @@
 			wpa_s->conf->wps_vendor_ext[i];
 	}
 
-	if (num_vendor_extensions &&
-	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
-					       "VendorExtension",
-					       vendor_ext,
-					       num_vendor_extensions))
-		goto err_no_mem;
-
-	/* GO Intent */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
-					 wpa_s->conf->p2p_go_intent))
-		goto err_no_mem;
-
-	/* Persistent Reconnect */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
-				       wpa_s->conf->persistent_reconnect))
-		goto err_no_mem;
-
-	/* Listen Reg Class */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
-					 wpa_s->conf->p2p_listen_reg_class))
-		goto err_no_mem;
-
-	/* Listen Channel */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
-					 wpa_s->conf->p2p_listen_channel))
-		goto err_no_mem;
-
-	/* Oper Reg Class */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
-					 wpa_s->conf->p2p_oper_reg_class))
-		goto err_no_mem;
-
-	/* Oper Channel */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
-					 wpa_s->conf->p2p_oper_channel))
-		goto err_no_mem;
-
-	/* SSID Postfix */
-	if (wpa_s->conf->p2p_ssid_postfix &&
-	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
-					 wpa_s->conf->p2p_ssid_postfix))
-		goto err_no_mem;
-
-	/* Intra Bss */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
-				       wpa_s->conf->p2p_intra_bss))
-		goto err_no_mem;
-
-	/* Group Idle */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
-					 wpa_s->conf->p2p_group_idle))
-		goto err_no_mem;
-
-	/* Dissasociation low ack */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
-					 wpa_s->conf->disassoc_low_ack))
-		goto err_no_mem;
-
-	/* No Group Iface */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
-				       wpa_s->conf->p2p_no_group_iface))
-		goto err_no_mem;
-
-	/* P2P Search Delay */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
-					 wpa_s->conf->p2p_search_delay))
-		goto err_no_mem;
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	if ((num_vendor_extensions &&
+	     !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+						"VendorExtension",
+						vendor_ext,
+						num_vendor_extensions)) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+					 wpa_s->conf->p2p_go_intent) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
+				       wpa_s->conf->persistent_reconnect) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+					 wpa_s->conf->p2p_listen_reg_class) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+					 wpa_s->conf->p2p_listen_channel) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+					 wpa_s->conf->p2p_oper_reg_class) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+					 wpa_s->conf->p2p_oper_channel) ||
+	    (wpa_s->conf->p2p_ssid_postfix &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+					  wpa_s->conf->p2p_ssid_postfix)) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+				       wpa_s->conf->p2p_intra_bss) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+					 wpa_s->conf->p2p_group_idle) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+					 wpa_s->conf->disassoc_low_ack) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
+				       wpa_s->conf->p2p_no_group_iface) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
+					 wpa_s->conf->p2p_search_delay) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
 	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto err_no_mem;
 
@@ -955,8 +922,8 @@
 			wpa_s->conf->changed_parameters |=
 					CFG_CHANGED_SEC_DEVICE_TYPE;
 		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
 				goto error;
 
@@ -972,30 +939,30 @@
 				} else
 					wpa_s->conf->wps_vendor_ext[i] = NULL;
 			}
-		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32) &&
+		} else if (os_strcmp(entry.key, "GOIntent") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32 &&
 			   (entry.uint32_value <= 15))
 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
-		else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
-			 (entry.type == DBUS_TYPE_BOOLEAN))
+		else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
+			 entry.type == DBUS_TYPE_BOOLEAN)
 			wpa_s->conf->persistent_reconnect = entry.bool_value;
-		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
-			 (entry.type == DBUS_TYPE_UINT32)) {
+		else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
+			 entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
-		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
-		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_OPER_CHANNEL;
-		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "OperChannel") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_OPER_CHANNEL;
@@ -1014,13 +981,13 @@
 
 			wpa_s->conf->changed_parameters |=
 					CFG_CHANGED_P2P_SSID_POSTFIX;
-		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+		} else if (os_strcmp(entry.key, "IntraBss") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_INTRA_BSS;
-		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32))
+		} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32)
 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
 		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
 			 entry.type == DBUS_TYPE_UINT32)
@@ -1300,8 +1267,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data)
+						    DBusError *error,
+						    void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1325,8 +1292,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+					    DBusError *error,
+					    void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1350,8 +1317,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data)
+							DBusError *error,
+							void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1409,8 +1376,7 @@
 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
 				  peer_args->p2p_device_addr, 0);
 	if (info == NULL) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "failed to find peer");
+		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
 		return FALSE;
 	}
 
@@ -1418,18 +1384,13 @@
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message 1", __func__);
 		return FALSE;
 	}
 
@@ -1444,29 +1405,14 @@
 			if (!dbus_message_iter_open_container(
 				    &array_iter, DBUS_TYPE_ARRAY,
 				    DBUS_TYPE_BYTE_AS_STRING,
-				    &inner_array_iter)) {
-				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 3 (%d)",
-					       __func__, i);
-				return FALSE;
-			}
-
-			if (!dbus_message_iter_append_fixed_array(
+				    &inner_array_iter) ||
+			    !dbus_message_iter_append_fixed_array(
 				    &inner_array_iter, DBUS_TYPE_BYTE,
-				    &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
-				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 4 (%d)",
-					       __func__, i);
-				return FALSE;
-			}
-
-			if (!dbus_message_iter_close_container(
+				    &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
+			    !dbus_message_iter_close_container(
 				    &array_iter, &inner_array_iter)) {
 				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 5 (%d)",
+					       "%s: failed to construct message 2 (%d)",
 					       __func__, i);
 				return FALSE;
 			}
@@ -1475,15 +1421,10 @@
 		}
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 6", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 7", __func__);
+			       "%s: failed to construct message 3", __func__);
 		return FALSE;
 	}
 
@@ -1695,15 +1636,6 @@
 	unsigned int i = 0, num = 0;
 	dbus_bool_t success = FALSE;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "An error occurred getting persistent groups list",
-			   __func__);
-		dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
-				     "occurred getting persistent groups list");
-		return FALSE;
-	}
-
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
 		if (network_is_persistent_group(ssid))
 			num++;
@@ -1816,12 +1748,12 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "Cannot add new persistent group", __func__);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: Cannot add new persistent group",
+			   __func__);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"wpa_supplicant could not add "
-			"a persistent group on this interface.");
+			"wpa_supplicant could not add a persistent group on this interface.");
 		goto err;
 	}
 
@@ -1834,13 +1766,12 @@
 
 	dbus_error_init(&error);
 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
-		wpa_printf(MSG_DEBUG, "dbus: %s: "
-			   "Control interface could not set persistent group "
-			   "properties", __func__);
-		reply = wpas_dbus_reply_new_from_error(message, &error,
-						       DBUS_ERROR_INVALID_ARGS,
-						       "Failed to set network "
-						       "properties");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: %s: Control interface could not set persistent group properties",
+			   __func__);
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_INVALID_ARGS,
+			"Failed to set network properties");
 		dbus_error_free(&error);
 		goto err;
 	}
@@ -1852,15 +1783,13 @@
 
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
@@ -1890,7 +1819,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *persistent_group_id = NULL;
+	char *iface = NULL, *persistent_group_id;
 	int id;
 	struct wpa_ssid *ssid;
 
@@ -1901,10 +1830,11 @@
 	 * Extract the network ID and ensure the network is actually a child of
 	 * this interface.
 	 */
-	iface = wpas_dbus_new_decompose_object_path(op, 1,
-						    &persistent_group_id,
-						    NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+	iface = wpas_dbus_new_decompose_object_path(
+		op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+		&persistent_group_id);
+	if (iface == NULL || persistent_group_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
@@ -1924,19 +1854,17 @@
 	wpas_notify_persistent_group_removed(wpa_s, ssid);
 
 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "error occurred when removing persistent group %d",
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: error occurred when removing persistent group %d",
 			   __func__, id);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"error removing the specified persistent group on "
-			"this interface.");
+			"error removing the specified persistent group on this interface.");
 		goto out;
 	}
 
 out:
 	os_free(iface);
-	os_free(persistent_group_id);
 	return reply;
 }
 
@@ -1947,8 +1875,8 @@
 	wpas_notify_persistent_group_removed(wpa_s, ssid);
 
 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "error occurred when removing persistent group %d",
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: error occurred when removing persistent group %d",
 			   __func__, ssid->id);
 		return;
 	}
@@ -2056,6 +1984,7 @@
 					    DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
+
 	if (wpa_s->current_ssid == NULL)
 		return FALSE;
 	return wpas_dbus_simple_array_property_getter(
@@ -2116,15 +2045,14 @@
 						  void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	u8 role = wpas_get_p2p_role(wpa_s);
-	char *p_pass = NULL;
+	char *p_pass;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-	/* Verify correct role for this property */
-	if (role == WPAS_P2P_ROLE_GO) {
-		if (wpa_s->current_ssid == NULL)
-			return FALSE;
-		p_pass = wpa_s->current_ssid->passphrase;
-	} else
+	if (ssid == NULL)
+		return FALSE;
+
+	p_pass = ssid->passphrase;
+	if (!p_pass)
 		p_pass = "";
 
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -2137,20 +2065,20 @@
 					   DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	u8 role = wpas_get_p2p_role(wpa_s);
 	u8 *p_psk = NULL;
 	u8 psk_len = 0;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-	/* Verify correct role for this property */
-	if (role == WPAS_P2P_ROLE_CLIENT) {
-		if (wpa_s->current_ssid == NULL)
-			return FALSE;
-		p_psk = wpa_s->current_ssid->psk;
-		psk_len = 32;
+	if (ssid == NULL)
+		return FALSE;
+
+	if (ssid->psk_set) {
+		p_psk = ssid->psk;
+		psk_len = sizeof(ssid->psk);
 	}
 
 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
-						      &p_psk, psk_len, error);
+						      p_psk, psk_len, error);
 }
 
 
@@ -2194,7 +2122,7 @@
 						  void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	DBusMessageIter variant_iter, iter_dict;
+	DBusMessageIter variant_iter, iter_dict, array_iter, sub;
 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
 	unsigned int i;
 	struct hostapd_data *hapd = NULL;
@@ -2206,6 +2134,82 @@
 		return FALSE;
 
 	dbus_message_iter_recurse(iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
+		return FALSE;
+
+	/*
+	 * This is supposed to be array of bytearrays (aay), but the earlier
+	 * implementation used a dict with "WPSVendorExtensions" as the key in
+	 * this setter function which does not match the format used by the
+	 * getter function. For backwards compatibility, allow both formats to
+	 * be used in the setter.
+	 */
+	if (dbus_message_iter_get_element_type(&variant_iter) ==
+	    DBUS_TYPE_ARRAY) {
+		/* This is the proper format matching the getter */
+		struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
+
+		dbus_message_iter_recurse(&variant_iter, &array_iter);
+
+		if (dbus_message_iter_get_arg_type(&array_iter) !=
+		    DBUS_TYPE_ARRAY ||
+		    dbus_message_iter_get_element_type(&array_iter) !=
+		    DBUS_TYPE_BYTE) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: Not an array of array of bytes");
+			return FALSE;
+		}
+
+		i = 0;
+		os_memset(vals, 0, sizeof(vals));
+
+		while (dbus_message_iter_get_arg_type(&array_iter) ==
+		       DBUS_TYPE_ARRAY) {
+			char *val;
+			int len;
+
+			if (i == MAX_WPS_VENDOR_EXTENSIONS) {
+				wpa_printf(MSG_DEBUG,
+					   "dbus: Too many WPSVendorExtensions values");
+				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+				break;
+			}
+
+			dbus_message_iter_recurse(&array_iter, &sub);
+			dbus_message_iter_get_fixed_array(&sub, &val, &len);
+			wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
+				    val, len);
+			vals[i] = wpabuf_alloc_copy(val, len);
+			if (vals[i] == NULL) {
+				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+				break;
+			}
+			i++;
+			dbus_message_iter_next(&array_iter);
+		}
+
+		if (i > MAX_WPS_VENDOR_EXTENSIONS) {
+			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+				wpabuf_free(vals[i]);
+			return FALSE;
+		}
+
+		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+			wpabuf_free(hapd->conf->wps_vendor_ext[i]);
+			hapd->conf->wps_vendor_ext[i] = vals[i];
+		}
+
+		hostapd_update_wps(hapd);
+
+		return TRUE;
+	}
+
+	if (dbus_message_iter_get_element_type(&variant_iter) !=
+	    DBUS_TYPE_DICT_ENTRY)
+		return FALSE;
+
+	wpa_printf(MSG_DEBUG,
+		   "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
 		return FALSE;
 
@@ -2223,6 +2227,7 @@
 				goto error;
 
 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+				wpabuf_free(hapd->conf->wps_vendor_ext[i]);
 				if (i < entry.array_len) {
 					hapd->conf->wps_vendor_ext[i] =
 						entry.binarray_value[i];
@@ -2271,30 +2276,31 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "service_type") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+		if (os_strcmp(entry.key, "service_type") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
-			else if (!os_strcmp(entry.str_value, "bonjour"))
+			else if (os_strcmp(entry.str_value, "bonjour") == 0)
 				bonjour = 1;
 			else
 				goto error_clear;
-		} else if (!os_strcmp(entry.key, "version") &&
-		           entry.type == DBUS_TYPE_INT32) {
+		} else if (os_strcmp(entry.key, "version") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			version = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "service") &&
-			     (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "service") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			os_free(service);
 			service = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "query")) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != DBUS_TYPE_BYTE))
+		} else if (os_strcmp(entry.key, "query") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
 			query = wpabuf_alloc_copy(
 				entry.bytearray_value,
 				entry.array_len);
-		} else if (!os_strcmp(entry.key, "response")) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != DBUS_TYPE_BYTE))
+		} else if (os_strcmp(entry.key, "response") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
 			resp = wpabuf_alloc_copy(entry.bytearray_value,
 						 entry.array_len);
@@ -2309,8 +2315,6 @@
 		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
 			goto error;
 
-		os_free(service);
-		service = NULL;
 	} else if (bonjour == 1) {
 		if (query == NULL || resp == NULL)
 			goto error;
@@ -2322,6 +2326,7 @@
 	} else
 		goto error;
 
+	os_free(service);
 	return reply;
 error_clear:
 	wpa_dbus_dict_entry_clear(&entry);
@@ -2356,11 +2361,11 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "service_type") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+		if (os_strcmp(entry.key, "service_type") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
-			else if (!os_strcmp(entry.str_value, "bonjour"))
+			else if (os_strcmp(entry.str_value, "bonjour") == 0)
 				bonjour = 1;
 			else
 				goto error_clear;
@@ -2371,13 +2376,14 @@
 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
-			if (!os_strcmp(entry.key, "version") &&
+			if (os_strcmp(entry.key, "version") == 0 &&
 			    entry.type == DBUS_TYPE_INT32)
 				version = entry.uint32_value;
-			else if (!os_strcmp(entry.key, "service") &&
-				 entry.type == DBUS_TYPE_STRING)
+			else if (os_strcmp(entry.key, "service") == 0 &&
+				 entry.type == DBUS_TYPE_STRING) {
+				os_free(service);
 				service = os_strdup(entry.str_value);
-			else
+			} else
 				goto error_clear;
 
 			wpa_dbus_dict_entry_clear(&entry);
@@ -2387,7 +2393,6 @@
 			goto error;
 
 		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
-		os_free(service);
 		if (ret != 0)
 			goto error;
 	} else if (bonjour == 1) {
@@ -2395,10 +2400,11 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 
-			if (!os_strcmp(entry.key, "query")) {
-				if ((entry.type != DBUS_TYPE_ARRAY) ||
-				    (entry.array_type != DBUS_TYPE_BYTE))
+			if (os_strcmp(entry.key, "query") == 0) {
+				if (entry.type != DBUS_TYPE_ARRAY ||
+				    entry.array_type != DBUS_TYPE_BYTE)
 					goto error_clear;
+				wpabuf_free(query);
 				query = wpabuf_alloc_copy(
 					entry.bytearray_value,
 					entry.array_len);
@@ -2414,14 +2420,17 @@
 		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
 		if (ret != 0)
 			goto error;
-		wpabuf_free(query);
 	} else
 		goto error;
 
+	wpabuf_free(query);
+	os_free(service);
 	return reply;
 error_clear:
 	wpa_dbus_dict_entry_clear(&entry);
 error:
+	wpabuf_free(query);
+	os_free(service);
 	return wpas_dbus_error_invalid_args(message, NULL);
 }
 
@@ -2457,22 +2466,22 @@
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
-		if (!os_strcmp(entry.key, "peer_object") &&
+		if (os_strcmp(entry.key, "peer_object") == 0 &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "service_type") &&
+		} else if (os_strcmp(entry.key, "service_type") == 0 &&
 			   entry.type == DBUS_TYPE_STRING) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
 			else
 				goto error_clear;
-		} else if (!os_strcmp(entry.key, "version") &&
+		} else if (os_strcmp(entry.key, "version") == 0 &&
 			   entry.type == DBUS_TYPE_INT32) {
 			version = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "service") &&
+		} else if (os_strcmp(entry.key, "service") == 0 &&
 			   entry.type == DBUS_TYPE_STRING) {
 			service = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "tlv")) {
+		} else if (os_strcmp(entry.key, "tlv") == 0) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -2550,16 +2559,17 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "peer_object") &&
+		if (os_strcmp(entry.key, "peer_object") == 0 &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "frequency") &&
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
 			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "dialog_token") &&
-			   entry.type == DBUS_TYPE_UINT32) {
+		} else if (os_strcmp(entry.key, "dialog_token") == 0 &&
+			   (entry.type == DBUS_TYPE_UINT32 ||
+			    entry.type == DBUS_TYPE_INT32)) {
 			dlg_tok = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "tlvs")) {
+		} else if (os_strcmp(entry.key, "tlvs") == 0) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -2570,12 +2580,9 @@
 
 		wpa_dbus_dict_entry_clear(&entry);
 	}
-	if (!peer_object_path ||
-	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
-	    !p2p_peer_known(wpa_s->global->p2p, addr))
-		goto error;
-
-	if (tlv == NULL)
+	if (parse_peer_object_path(peer_object_path, addr) < 0 ||
+	    !p2p_peer_known(wpa_s->global->p2p, addr) ||
+	    tlv == NULL)
 		goto error;
 
 	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 6e67c89..fdaccba 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -109,34 +109,34 @@
  */
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
+						  DBusError *error,
+						  void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
 	DBusMessageIter *iter, DBusError *error, void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data);
+						    DBusError *error,
+						    void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
+					    DBusError *error,
+					    void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data);
+							DBusError *error,
+							void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data);
+						       DBusError *error,
+						       void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
 	DBusMessageIter *iter, DBusError *error, void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data);
+						       DBusError *error,
+						       void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
 					  DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 4226f2f..a94a0e5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -41,8 +41,8 @@
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
 	if (dbus_message_iter_get_arg_type(&variant_iter) !=
 	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
-			   "string required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Role type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Role must be a string");
 		return -1;
@@ -70,10 +70,9 @@
 	char *val;
 
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
-			   "string required");
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Type type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Type must be a string");
 		return -1;
@@ -105,8 +104,8 @@
 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(&variant_iter) !=
 	    DBUS_TYPE_BYTE) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
-			   "byte array required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Bssid type, byte array required");
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Bssid must be a byte array");
 		return -1;
@@ -114,8 +113,8 @@
 	dbus_message_iter_recurse(&variant_iter, &array_iter);
 	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
 	if (len != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
-			   "%d", len);
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length %d",
+			   len);
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Bssid is wrong length");
 		return -1;
@@ -132,10 +131,9 @@
 	DBusMessageIter variant_iter;
 
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
-			   "string required");
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Pin type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Pin must be a string");
 		return -1;
@@ -158,8 +156,8 @@
 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(&variant_iter) !=
 	    DBUS_TYPE_BYTE) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
-			   "P2PDeviceAddress type, byte array required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong P2PDeviceAddress type, byte array required");
 		*reply = wpas_dbus_error_invalid_args(
 			message, "P2PDeviceAddress must be a byte array");
 		return -1;
@@ -168,11 +166,11 @@
 	dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
 					  &len);
 	if (len != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
-			   "P2PDeviceAddress length %d", len);
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "P2PDeviceAddress "
-						      "has wrong length");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong P2PDeviceAddress length %d",
+			   len);
+		*reply = wpas_dbus_error_invalid_args(
+			message, "P2PDeviceAddress has wrong length");
 		return -1;
 	}
 	return 0;
@@ -249,54 +247,54 @@
 		dbus_message_iter_next(&dict_iter);
 	}
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface && params.type == 1) {
+		if (params.pin == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: WPS.Start - Pin required for registrar role");
+			return wpas_dbus_error_invalid_args(
+				message, "Pin required for registrar role.");
+		}
+		ret = wpa_supplicant_ap_wps_pin(wpa_s,
+						params.bssid,
+						params.pin,
+						npin, sizeof(npin), 0);
+	} else if (wpa_s->ap_iface) {
+		ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+						params.bssid,
+						params.p2p_dev_addr);
+	} else
+#endif /* CONFIG_AP */
 	if (params.role == 0) {
 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
 		return wpas_dbus_error_invalid_args(message,
 						    "Role not specified");
-	} else if (params.role == 1 && params.type == 0) {
+	} else if (params.role == 2) {
+		if (params.pin == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: WPS.Start - Pin required for registrar role");
+			return wpas_dbus_error_invalid_args(
+				message, "Pin required for registrar role.");
+		}
+		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
+					 NULL);
+	} else if (params.type == 0) {
 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
 		return wpas_dbus_error_invalid_args(message,
 						    "Type not specified");
-	} else if (params.role == 2 && params.pin == NULL) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
-			   "registrar role");
-		return wpas_dbus_error_invalid_args(
-			message, "Pin required for registrar role.");
-	}
-
-	if (params.role == 2)
-		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
-					 NULL);
-	else if (params.type == 1) {
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface)
-			ret = wpa_supplicant_ap_wps_pin(wpa_s,
-							params.bssid,
-							params.pin,
-							npin, sizeof(npin), 0);
-		else
-#endif /* CONFIG_AP */
-		{
-			ret = wpas_wps_start_pin(wpa_s, params.bssid,
-						 params.pin, 0,
-						 DEV_PW_DEFAULT);
-			if (ret > 0)
-				os_snprintf(npin, sizeof(npin), "%08d", ret);
-		}
+	} else if (params.type == 1) {
+		ret = wpas_wps_start_pin(wpa_s, params.bssid,
+					 params.pin, 0,
+					 DEV_PW_DEFAULT);
+		if (ret > 0)
+			os_snprintf(npin, sizeof(npin), "%08d", ret);
 	} else {
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface)
-			ret = wpa_supplicant_ap_wps_pbc(wpa_s,
-							params.bssid,
-							params.p2p_dev_addr);
-		else
-#endif /* CONFIG_AP */
 		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
 	}
 
 	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
-			   "role %s and key %s",
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start wpas_wps_failed in role %s and key %s",
 			   (params.role == 1 ? "enrollee" : "registrar"),
 			   (params.type == 0 ? "" :
 			    (params.type == 1 ? "pin" : "pbc")));
@@ -305,31 +303,16 @@
 	}
 
 	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
+	if (!reply)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    (os_strlen(npin) > 0 &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	if (os_strlen(npin) > 0) {
-		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
-			dbus_message_unref(reply);
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_NO_MEMORY,
-						      NULL);
-		}
-	}
-
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -351,7 +334,8 @@
 						 void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
+	dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
 						&process, error);
 }
@@ -378,7 +362,7 @@
 					      &process_credentials))
 		return FALSE;
 
-	old_pc = (wpa_s->conf->wps_cred_processing != 1);
+	old_pc = wpa_s->conf->wps_cred_processing != 1;
 	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
 
 	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 8df7ac1..15b0901 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -15,6 +15,7 @@
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_new_helpers.h"
+#include "dbus_new_handlers.h"
 #include "dbus_dict_helpers.h"
 
 
@@ -73,46 +74,36 @@
  * with properties names as keys and theirs values as values.
  */
 static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
-				        struct wpa_dbus_object_desc *obj_dsc)
+					struct wpa_dbus_object_desc *obj_dsc)
 {
 	DBusMessage *reply;
 	DBusMessageIter iter, dict_iter;
 	DBusError error;
 
 	reply = dbus_message_new_method_return(message);
-	if (reply == NULL) {
-		wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
-			   __func__);
-		return NULL;
-	}
+	if (reply == NULL)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
-		wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
-			   __func__);
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       "out of memory");
-		return reply;
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	dbus_error_init(&error);
 	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
-				       interface, obj_dsc->user_data, &error))
-	{
+				       interface, obj_dsc->user_data, &error)) {
 		dbus_message_unref(reply);
-		reply = wpas_dbus_reply_new_from_error(message, &error,
-						       DBUS_ERROR_INVALID_ARGS,
-						       "No readable properties"
-						       " in this interface");
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_INVALID_ARGS,
+			"No readable properties in this interface");
 		dbus_error_free(&error);
 		return reply;
 	}
 
 	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      "out of memory");
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -135,6 +126,7 @@
 	for (arg = method_dsc->args; arg && arg->name; arg++) {
 		if (arg->dir == ARG_IN) {
 			size_t blen = registered_sig + MAX_SIG_LEN - pos;
+
 			ret = os_snprintf(pos, blen, "%s", arg->type);
 			if (os_snprintf_error(blen, ret))
 				return 0;
@@ -270,10 +262,13 @@
 	}
 
 	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
-		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
+		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) {
+		wpa_printf(MSG_MSGDUMP, "%s: Get(%s)", __func__, property);
 		return properties_get(message, property_dsc,
 				      obj_dsc->user_data);
+	}
 
+	wpa_printf(MSG_MSGDUMP, "%s: Set(%s)", __func__, property);
 	return properties_set(message, property_dsc, obj_dsc->user_data);
 }
 
@@ -295,8 +290,7 @@
 	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
 			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
 		/* First argument: interface name (DBUS_TYPE_STRING) */
-		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		{
+		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 			return dbus_message_new_error(message,
 						      DBUS_ERROR_INVALID_ARGS,
 						      NULL);
@@ -352,8 +346,7 @@
 					      NULL);
 	}
 
-	return method_dsc->method_handler(message,
-					  obj_dsc->user_data);
+	return method_dsc->method_handler(message, obj_dsc->user_data);
 }
 
 
@@ -388,8 +381,9 @@
 	if (!method || !path || !msg_interface)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
-		   msg_interface, method, path);
+	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
 
 	/* if message is introspection method call */
 	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
@@ -401,8 +395,7 @@
 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
 		reply = dbus_message_new_error(
 			message, DBUS_ERROR_UNKNOWN_METHOD,
-			"wpa_supplicant was compiled without "
-			"introspection support.");
+			"wpa_supplicant was compiled without introspection support.");
 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
 	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
 			     WPAS_DBUS_INTERFACE_MAX)) {
@@ -455,6 +448,7 @@
 	free_dbus_object_desc(obj_dsc);
 }
 
+
 /**
  * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
  * @application_data: Pointer to application specific data structure
@@ -482,30 +476,28 @@
 	obj_desc->path = os_strdup(dbus_path);
 
 	/* Register the message handler for the global dbus interface */
-	if (!dbus_connection_register_object_path(iface->con,
-						  dbus_path, &wpa_vtable,
-						  obj_desc)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
+	if (!dbus_connection_register_object_path(iface->con, dbus_path,
+						  &wpa_vtable, obj_desc)) {
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
 		return -1;
 	}
 
 	/* Register our service with the message bus */
 	dbus_error_init(&error);
-	switch (dbus_bus_request_name(iface->con, dbus_service,
-				      0, &error)) {
+	switch (dbus_bus_request_name(iface->con, dbus_service, 0, &error)) {
 	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
 		ret = 0;
 		break;
 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: already registered");
 		break;
 	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: %s %s",
+			   error.name, error.message);
 		break;
 	}
 	dbus_error_free(&error);
@@ -529,14 +521,12 @@
  *
  * Registers a new interface with dbus and assigns it a dbus object path.
  */
-int wpa_dbus_register_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface,
-	const char *path, const char *ifname,
-	struct wpa_dbus_object_desc *obj_desc)
+int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv *ctrl_iface,
+				       const char *path, const char *ifname,
+				       struct wpa_dbus_object_desc *obj_desc)
 {
 	DBusConnection *con;
 	DBusError error;
-
 	DBusObjectPathVTable vtable = {
 		&free_dbus_object_desc_cb, &message_handler,
 		NULL, NULL, NULL, NULL
@@ -554,14 +544,12 @@
 	/* Register the message handler for the interface functions */
 	if (!dbus_connection_try_register_object_path(con, path, &vtable,
 						      obj_desc, &error)) {
-		if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+		if (os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
 			wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
 		} else {
-			wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-				   "handler for interface %s object %s",
-				   ifname, path);
-			wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
-			wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+			wpa_printf(MSG_ERROR,
+				   "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
+				   ifname, path, error.name, error.message);
 		}
 		dbus_error_free(&error);
 		return -1;
@@ -591,8 +579,9 @@
 
 	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
-			   "private data: %s", __func__, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: Could not obtain object's private data: %s",
+			   __func__, path);
 		return 0;
 	}
 
@@ -626,24 +615,22 @@
 
 		if (!dbus_message_iter_open_container(dict_iter,
 						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter))
-			return FALSE;
-
-		if (!dbus_message_iter_append_basic(&entry_iter,
+						      NULL, &entry_iter) ||
+		    !dbus_message_iter_append_basic(&entry_iter,
 						    DBUS_TYPE_STRING,
 						    &dsc->dbus_property))
 			return FALSE;
 
 		dbus_error_init(&error);
 		if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
-			if (dbus_error_is_set (&error)) {
-				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
-					   "new value of property %s: (%s) %s",
-				           __func__, dsc->dbus_property,
-				           error.name, error.message);
+			if (dbus_error_is_set(&error)) {
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s: Cannot get new value of property %s: (%s) %s",
+					   __func__, dsc->dbus_property,
+					   error.name, error.message);
 			} else {
-				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
-					   "new value of property %s",
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s: Cannot get new value of property %s",
 					   __func__, dsc->dbus_property);
 			}
 			dbus_error_free(&error);
@@ -673,38 +660,23 @@
 	dbus_message_iter_init_append(msg, &signal_iter);
 
 	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
-					    &interface))
-		goto err;
+					    &interface) ||
+	    /* Changed properties dict */
+	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "{sv}", &dict_iter) ||
+	    !put_changed_properties(obj_dsc, interface, &dict_iter, 0) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter) ||
+	    /* Invalidated properties array (empty) */
+	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "s", &dict_iter) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+			   __func__);
+	} else {
+		dbus_connection_send(con, msg, NULL);
+	}
 
-	/* Changed properties dict */
-	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "{sv}", &dict_iter))
-		goto err;
-
-	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	/* Invalidated properties array (empty) */
-	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "s", &dict_iter))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	dbus_connection_send(con, msg, NULL);
-
-out:
 	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
-		   __func__);
-	goto out;
 }
 
 
@@ -722,25 +694,16 @@
 	dbus_message_iter_init_append(msg, &signal_iter);
 
 	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "{sv}", &dict_iter))
-		goto err;
+					      "{sv}", &dict_iter) ||
+	    !put_changed_properties(obj_dsc, interface, &dict_iter, 1) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+			   __func__);
+	} else {
+		dbus_connection_send(con, msg, NULL);
+	}
 
-	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	dbus_connection_send(con, msg, NULL);
-
-out:
 	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
-		   __func__);
-	goto out;
 }
 
 
@@ -772,8 +735,9 @@
 	DBusConnection *con = eloop_ctx;
 	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
 
-	wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
-		   "of object %s", __func__, obj_desc->path);
+	wpa_printf(MSG_DEBUG,
+		   "dbus: %s: Timeout - sending changed properties of object %s",
+		   __func__, obj_desc->path);
 	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
 }
 
@@ -884,8 +848,9 @@
 	dbus_connection_get_object_path_data(iface->con, path,
 					     (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "could not obtain object's private data: %s", path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
+			   path);
 		return;
 	}
 
@@ -898,13 +863,14 @@
 		}
 
 	if (!dsc || !dsc->dbus_property) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "no property %s in object %s", property, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: wpa_dbus_property_changed: no property %s in object %s",
+			   property, path);
 		return;
 	}
 
 	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
-					 iface->con, obj_desc->path)) {
+					 iface->con, obj_desc)) {
 		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
 				       flush_object_timeout_handler,
 				       iface->con, obj_desc);
@@ -936,8 +902,9 @@
 	dbus_connection_get_object_path_data(iface->con, path,
 					     (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
-		           "private data: %s", __func__, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: could not obtain object's private data: %s",
+			   __func__, path);
 		return FALSE;
 	}
 
@@ -951,10 +918,11 @@
 	if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
 				       interface, obj_desc->user_data,
 				       &error)) {
-		wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
-		           " properties: (%s) %s", __func__,
-		           dbus_error_is_set(&error) ? error.name : "none",
-		           dbus_error_is_set(&error) ? error.message : "none");
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: failed to get object properties: (%s) %s",
+			   __func__,
+			   dbus_error_is_set(&error) ? error.name : "none",
+			   dbus_error_is_set(&error) ? error.message : "none");
 		dbus_error_free(&error);
 		return FALSE;
 	}
@@ -965,29 +933,34 @@
 /**
  * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
  * @path: The dbus object path
- * @p2p_persistent_group: indicates whether to parse the path as a P2P
- *                        persistent group object
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
+ * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
+ * @item: (out) The part following the specified separator, if any
+ * Returns: The object path of the interface this path refers to
  *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
+ * For a given object path, decomposes the object path into object id and
+ * requested part, if those parts exist. The caller is responsible for freeing
+ * the returned value. The *item pointer points to that allocated value and must
+ * not be freed separately.
+ *
+ * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
+ * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
+ * getting returned and *items set to point to "0".
  */
-char *wpas_dbus_new_decompose_object_path(const char *path,
-					   int p2p_persistent_group,
-					   char **network,
-					   char **bssid)
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+					   char **item)
 {
 	const unsigned int dev_path_prefix_len =
 		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
 	char *obj_path_only;
-	char *next_sep;
+	char *pos;
+	size_t sep_len;
 
-	/* Be a bit paranoid about path */
-	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-				dev_path_prefix_len))
-		return NULL;
+	*item = NULL;
+
+	/* Verify that this starts with our interface prefix */
+	if (os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+		       dev_path_prefix_len) != 0)
+		return NULL; /* not our path */
 
 	/* Ensure there's something at the end of the path */
 	if ((path + dev_path_prefix_len)[0] == '\0')
@@ -997,39 +970,20 @@
 	if (obj_path_only == NULL)
 		return NULL;
 
-	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-	if (next_sep != NULL) {
-		const char *net_part = os_strstr(
-			next_sep, p2p_persistent_group ?
-			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
-			WPAS_DBUS_NEW_NETWORKS_PART "/");
-		const char *bssid_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+	pos = obj_path_only + dev_path_prefix_len;
+	pos = os_strchr(pos, '/');
+	if (pos == NULL)
+		return obj_path_only; /* no next item on the path */
 
-		if (network && net_part) {
-			/* Deal with a request for a configured network */
-			const char *net_name = net_part +
-				os_strlen(p2p_persistent_group ?
-					  WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
-					  "/" :
-					  WPAS_DBUS_NEW_NETWORKS_PART "/");
-			*network = NULL;
-			if (os_strlen(net_name))
-				*network = os_strdup(net_name);
-		} else if (bssid && bssid_part) {
-			/* Deal with a request for a scanned BSSID */
-			const char *bssid_name = bssid_part +
-				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-			if (os_strlen(bssid_name))
-				*bssid = os_strdup(bssid_name);
-			else
-				*bssid = NULL;
-		}
+	 /* Separate network interface prefix from the path */
+	*pos++ = '\0';
 
-		/* Cut off interface object path before "/" */
-		*next_sep = '\0';
-	}
+	sep_len = os_strlen(sep);
+	if (os_strncmp(pos, sep, sep_len) != 0 || pos[sep_len] != '/')
+		return obj_path_only; /* no match */
 
+	 /* return a pointer to the requested item */
+	*item = pos + sep_len + 1;
 	return obj_path_only;
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 6d31ad5..6e2c1f1 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -12,13 +12,13 @@
 
 #include <dbus/dbus.h>
 
-typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
-					       void *user_data);
-typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
+typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
+					      void *user_data);
+typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
 
-typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
-                                                DBusError *error,
-						void *user_data);
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data);
 
 struct wpa_dbus_object_desc {
 	DBusConnection *connection;
@@ -137,10 +137,8 @@
 DBusMessage * wpa_dbus_introspect(DBusMessage *message,
 				  struct wpa_dbus_object_desc *obj_dsc);
 
-char *wpas_dbus_new_decompose_object_path(const char *path,
-					   int p2p_persistent_group,
-					   char **network,
-					   char **bssid);
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+					   char **item);
 
 DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
 					    DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index 3b090c0..6209c67 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -37,14 +37,16 @@
 	iface = os_zalloc(sizeof(struct interfaces));
 	if (!iface)
 		return NULL;
+	iface->dbus_interface = os_strdup(dbus_interface);
 	iface->xml = wpabuf_alloc(6000);
-	if (iface->xml == NULL) {
+	if (iface->dbus_interface == NULL || iface->xml == NULL) {
+		os_free(iface->dbus_interface);
+		wpabuf_free(iface->xml);
 		os_free(iface);
 		return NULL;
 	}
 	wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
 	dl_list_add_tail(list, &iface->list);
-	iface->dbus_interface = os_strdup(dbus_interface);
 	return iface;
 }
 
@@ -96,6 +98,7 @@
 {
 	const struct wpa_dbus_method_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -110,6 +113,7 @@
 {
 	const struct wpa_dbus_signal_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -124,6 +128,7 @@
 {
 	const struct wpa_dbus_property_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -154,14 +159,14 @@
 static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
 {
 	struct interfaces *iface, *n;
+
 	dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
 		if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
 			wpabuf_put_buf(xml, iface->xml);
 			wpabuf_put_str(xml, "</interface>");
 		} else {
-			wpa_printf(MSG_DEBUG, "dbus: Not enough room for "
-				   "add_interfaces inspect data: tailroom %u, "
-				   "add %u",
+			wpa_printf(MSG_DEBUG,
+				   "dbus: Not enough room for add_interfaces inspect data: tailroom %u, add %u",
 				   (unsigned int) wpabuf_tailroom(xml),
 				   (unsigned int) wpabuf_len(iface->xml));
 		}
@@ -229,6 +234,7 @@
 				struct wpa_dbus_object_desc *obj_dsc)
 {
 	struct dl_list ifaces;
+
 	dl_list_init(&ifaces);
 	extract_interfaces(&ifaces, obj_dsc);
 	add_interfaces(&ifaces, xml);
@@ -270,6 +276,7 @@
 	reply = dbus_message_new_method_return(message);
 	if (reply) {
 		const char *intro_str = wpabuf_head(xml);
+
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
 					 DBUS_TYPE_INVALID);
 	}
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index a86d39f..45bb402 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -92,9 +92,9 @@
  */
 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
+	return dbus_message_new_error(
+		message, WPAS_ERROR_INVALID_IFACE,
+		"wpa_supplicant knows nothing about this interface.");
 }
 
 
@@ -216,8 +216,12 @@
 	if (!msg_interface)
 		goto out;
 
+	wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
+
 	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
-	                                                 &bssid);
+							 &bssid);
 	if (iface_obj_path == NULL) {
 		reply = wpas_dbus_new_invalid_iface_error(message);
 		goto out;
@@ -227,7 +231,7 @@
 	 * wpa_supplicant structure it's supposed to (which is wpa_s)
 	 */
 	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
-	                                          iface_obj_path) != wpa_s) {
+						  iface_obj_path) != wpa_s) {
 		reply = wpas_dbus_new_invalid_iface_error(message);
 		goto out;
 	}
@@ -235,6 +239,7 @@
 	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
 		/* A method for one of this interface's configured networks */
 		int nid = strtoul(network, NULL, 10);
+
 		if (errno != EINVAL)
 			reply = wpas_dispatch_network_method(message, wpa_s,
 							     nid);
@@ -275,25 +280,25 @@
 			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 #ifdef CONFIG_WPS
-		else if (!os_strcmp(method, "wpsPbc"))
+		else if (os_strcmp(method, "wpsPbc") == 0)
 			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
-		else if (!os_strcmp(method, "wpsPin"))
+		else if (os_strcmp(method, "wpsPin") == 0)
 			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
-		else if (!os_strcmp(method, "wpsReg"))
+		else if (os_strcmp(method, "wpsReg") == 0)
 			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
 #endif /* CONFIG_WPS */
-		else if (!os_strcmp(method, "flush"))
+		else if (os_strcmp(method, "flush") == 0)
 			reply = wpas_dbus_iface_flush(message, wpa_s);
 	}
 
 	/* If the message was handled, send back the reply */
+out:
 	if (reply) {
 		if (!dbus_message_get_no_reply(message))
 			dbus_connection_send(connection, reply, NULL);
 		dbus_message_unref(reply);
 	}
 
-out:
 	os_free(iface_obj_path);
 	os_free(network);
 	os_free(bssid);
@@ -328,6 +333,10 @@
 	if (!method || !path || !ctrl_iface || !msg_interface)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
+	wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
+
 	/* Validate the method interface */
 	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -381,8 +390,8 @@
 					  WPAS_DBUS_IFACE_INTERFACE,
 					  "ScanResultsAvailable");
 	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to send scan results signal");
 		return;
 	}
 	dbus_connection_send(iface->con, _signal, NULL);
@@ -426,9 +435,8 @@
 					  "StateChange");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
@@ -436,13 +444,12 @@
 	old_state_str = wpa_supplicant_state_txt(old_state);
 
 	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_STRING, &new_state_str,
-	                              DBUS_TYPE_STRING, &old_state_str,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_STRING, &new_state_str,
+				      DBUS_TYPE_STRING, &old_state_str,
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "Not enough memory to construct state change "
-		           "signal");
+			   "dbus: %s: Not enough memory to construct state change signal",
+			   __func__);
 		goto out;
 	}
 
@@ -474,18 +481,18 @@
 					  WPAS_DBUS_IFACE_INTERFACE,
 					  "Scanning");
 	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to send scan results signal");
 		return;
 	}
 
 	if (dbus_message_append_args(_signal,
-	                             DBUS_TYPE_BOOLEAN, &scanning,
-	                             DBUS_TYPE_INVALID)) {
+				     DBUS_TYPE_BOOLEAN, &scanning,
+				     DBUS_TYPE_INVALID)) {
 		dbus_connection_send(iface->con, _signal, NULL);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
-			   "signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to construct signal");
 	}
 	dbus_message_unref(_signal);
 }
@@ -510,19 +517,18 @@
 					  "WpsCred");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: Could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
 	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
 				      &cred->cred_attr, cred->cred_attr_len,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Not enough memory to construct signal");
+			   "dbus: %s: Not enough memory to construct signal",
+			   __func__);
 		goto out;
 	}
 
@@ -561,9 +567,8 @@
 					  "Certification");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_certification: "
-		           "Could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: Could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
@@ -572,15 +577,15 @@
 	cert_hex_len = cert ? wpabuf_len(cert) : 0;
 
 	if (!dbus_message_append_args(_signal,
-				      DBUS_TYPE_INT32,&depth,
+				      DBUS_TYPE_INT32, &depth,
 				      DBUS_TYPE_STRING, &subject,
-	                              DBUS_TYPE_STRING, &hash,
-	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      DBUS_TYPE_STRING, &hash,
+				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
 				      &cert_hex, cert_hex_len,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_certification: "
-		           "Not enough memory to construct signal");
+			   "dbus: %s: Not enough memory to construct signal",
+			   __func__);
 		goto out;
 	}
 
@@ -612,8 +617,7 @@
 	if (!dbus_connection_register_object_path(iface->con,
 						  WPAS_DBUS_PATH, &wpas_vtable,
 						  iface)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
 		return -1;
 	}
 
@@ -627,12 +631,13 @@
 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: already registered");
 		break;
 	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: %s %s",
+			   error.name, error.message);
 		break;
 	}
 	dbus_error_free(&error);
@@ -681,8 +686,9 @@
 	/* Register the message handler for the interface functions */
 	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
 					       wpa_s)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler for interface %s", wpa_s->ifname);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not set up message handler for interface %s",
+			   wpa_s->ifname);
 		return -1;
 	}
 
@@ -706,7 +712,7 @@
 	if (wpa_s == NULL || wpa_s->global == NULL)
 		return 0;
 	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
+	if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
 		return 0;
 
 	con = ctrl_iface->con;
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
index e668231..451a9f8 100644
--- a/wpa_supplicant/dbus/dbus_old.h
+++ b/wpa_supplicant/dbus/dbus_old.h
@@ -82,7 +82,7 @@
 					      const struct wpabuf *cert);
 
 char * wpas_dbus_decompose_object_path(const char *path, char **network,
-                                       char **bssid);
+				       char **bssid);
 
 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
@@ -104,7 +104,12 @@
 {
 }
 
-#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+static inline void
+wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+					enum wpa_states new_state,
+					enum wpa_states old_state)
+{
+}
 
 static inline void
 wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 0f1f5cf..773ee8b 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -37,9 +37,9 @@
 {
 	DBusMessage *reply;
 
-	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
-				       "Did not receive correct message "
-				       "arguments.");
+	reply = dbus_message_new_error(
+		message, WPAS_ERROR_INVALID_OPTS,
+		"Did not receive correct message arguments.");
 	if (arg != NULL)
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
 					 DBUS_TYPE_INVALID);
@@ -112,28 +112,28 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 			if (!strcmp(entry.key, "driver") &&
-			    (entry.type == DBUS_TYPE_STRING)) {
+			    entry.type == DBUS_TYPE_STRING) {
 				os_free(driver);
 				driver = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (driver == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "driver-params") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(driver_param);
 				driver_param = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (driver_param == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "config-file") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(confname);
 				confname = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (confname == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "bridge-ifname") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(bridge_ifname);
 				bridge_ifname = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
@@ -151,13 +151,13 @@
 	 * an error if we already control it.
 	 */
 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_EXISTS_ERROR,
-					       "wpa_supplicant already "
-					       "controls this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_EXISTS_ERROR,
+			"wpa_supplicant already controls this interface.");
 	} else {
 		struct wpa_supplicant *wpa_s;
 		struct wpa_interface iface;
+
 		os_memset(&iface, 0, sizeof(iface));
 		iface.ifname = ifname;
 		iface.driver = driver;
@@ -165,17 +165,17 @@
 		iface.confname = confname;
 		iface.bridge_ifname = bridge_ifname;
 		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+		wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+		if (wpa_s) {
 			const char *path = wpa_s->dbus_path;
+
 			reply = dbus_message_new_method_return(message);
 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
+						 &path, DBUS_TYPE_INVALID);
 		} else {
-			reply = dbus_message_new_error(message,
-						       WPAS_ERROR_ADD_ERROR,
-						       "wpa_supplicant "
-						       "couldn't grab this "
-						       "interface.");
+			reply = dbus_message_new_error(
+				message, WPAS_ERROR_ADD_ERROR,
+				"wpa_supplicant couldn't grab this interface.");
 		}
 	}
 
@@ -226,10 +226,9 @@
 	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
 		reply = wpas_dbus_new_success_reply(message);
 	} else {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_ERROR,
-					       "wpa_supplicant couldn't "
-					       "remove this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_REMOVE_ERROR,
+			"wpa_supplicant couldn't remove this interface.");
 	}
 
 out:
@@ -256,8 +255,8 @@
 	struct wpa_supplicant *wpa_s;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_STRING, &ifname,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_STRING, &ifname,
+				   DBUS_TYPE_INVALID)) {
 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
 		goto out;
 	}
@@ -271,8 +270,8 @@
 	path = wpa_s->dbus_path;
 	reply = dbus_message_new_method_return(message);
 	dbus_message_append_args(reply,
-	                         DBUS_TYPE_OBJECT_PATH, &path,
-	                         DBUS_TYPE_INVALID);
+				 DBUS_TYPE_OBJECT_PATH, &path,
+				 DBUS_TYPE_INVALID);
 
 out:
 	return reply;
@@ -298,10 +297,10 @@
 	dbus_bool_t debug_show_keys;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_INT32, &debug_level,
-	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
-	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_INT32, &debug_level,
+				   DBUS_TYPE_BOOLEAN, &debug_timestamp,
+				   DBUS_TYPE_BOOLEAN, &debug_show_keys,
+				   DBUS_TYPE_INVALID)) {
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 	}
 
@@ -409,84 +408,56 @@
 {
 	DBusMessage *reply;
 	DBusMessageIter iter, iter_dict;
-	const u8 *ie;
+	const u8 *wpa_ie, *rsn_ie, *wps_ie;
 
 	/* Dump the properties into a dbus message */
 	reply = dbus_message_new_method_return(message);
 
+	wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+
 	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-		goto error;
-
-	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+	if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
+	    !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
 					     (const char *) bss->bssid,
-					     ETH_ALEN))
-		goto error;
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
-						     (const char *) (ie + 2),
-						     ie[1]))
-			goto error;
+					     ETH_ALEN) ||
+	    !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
+					     (const char *) bss->ssid,
+					     bss->ssid_len) ||
+	    (wpa_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
+					      (const char *) wpa_ie,
+					      wpa_ie[1] + 2)) ||
+	    (rsn_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+					      (const char *) rsn_ie,
+					      rsn_ie[1] + 2)) ||
+	    (wps_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
+					     (const char *) wps_ie,
+					      wps_ie[1] + 2)) ||
+	    (bss->freq &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
+	    !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
+					 bss->caps) ||
+	    (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
+	    (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
+	    (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
+					wpa_bss_get_max_rate(bss) * 500000) ||
+	    !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
+		if (reply)
+			dbus_message_unref(reply);
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_INTERNAL_ERROR,
+			"an internal error occurred returning BSSID properties.");
 	}
 
-	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	if (bss->freq) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
-						bss->freq))
-			goto error;
-	}
-	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
-					 bss->caps))
-		goto error;
-	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
-		goto error;
-	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
-		goto error;
-	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
-		goto error;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
-					wpa_bss_get_max_rate(bss) * 500000))
-		goto error;
-
-	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-		goto error;
-
 	return reply;
-
-error:
-	if (reply)
-		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "BSSID properties.");
 }
 
 
@@ -546,6 +517,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = {"CCMP", "TKIP", "NONE"};
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "pairwise", args,
 				    ARRAY_SIZE(args)))
@@ -555,28 +527,17 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "CCMP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "TKIP")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "NONE")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -589,6 +550,7 @@
 			const char *args[] = {
 				"CCMP", "TKIP", "WEP104", "WEP40"
 			};
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "group", args,
 				    ARRAY_SIZE(args)))
@@ -601,31 +563,19 @@
 						      &iter_array))
 			goto error;
 
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP104"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP40"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+		if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "CCMP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "TKIP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WEP104")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WEP40")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -648,38 +598,23 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "NONE"))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "IEEE8021X"))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-EAP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-PSK"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "NONE") ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "IEEE8021X") ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-EAP")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-PSK")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-NONE")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -690,6 +625,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = { "RSN", "WPA" };
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "proto", args,
 				    ARRAY_SIZE(args)))
@@ -699,24 +635,16 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "RSN"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "RSN")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -727,6 +655,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "auth_alg", args,
 				    ARRAY_SIZE(args)))
@@ -736,28 +665,17 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "OPEN"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "SHARED"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "LEAP"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "OPEN")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "SHARED")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "LEAP")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -772,9 +690,9 @@
 error:
 	if (reply)
 		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "interface capabilities.");
+	return dbus_message_new_error(
+		message, WPAS_ERROR_INTERNAL_ERROR,
+		"an internal error occurred returning interface capabilities.");
 }
 
 
@@ -795,10 +713,9 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_ADD_NETWORK_ERROR,
-					       "wpa_supplicant could not add "
-					       "a network on this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_ADD_NETWORK_ERROR,
+			"wpa_supplicant could not add a network on this interface.");
 		goto out;
 	}
 	wpas_notify_network_added(wpa_s, ssid);
@@ -838,8 +755,8 @@
 	struct wpa_ssid *ssid;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_OBJECT_PATH, &op,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_OBJECT_PATH, &op,
+				   DBUS_TYPE_INVALID)) {
 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
 		goto out;
 	}
@@ -866,17 +783,17 @@
 
 	wpas_notify_network_removed(wpa_s, ssid);
 
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
-					       "error removing the specified "
-					       "on this interface.");
-		goto out;
-	}
-
 	if (ssid == wpa_s->current_ssid)
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
+			"error removing the specified on this interface.");
+		goto out;
+	}
+
 	reply = wpas_dbus_new_success_reply(message);
 
 out:
@@ -886,7 +803,7 @@
 }
 
 
-static const char *dont_quote[] = {
+static const char  const *dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
 	"bssid", NULL
@@ -896,8 +813,9 @@
 static dbus_bool_t should_quote_opt(const char *key)
 {
 	int i = 0;
+
 	while (dont_quote[i] != NULL) {
-		if (strcmp(key, dont_quote[i]) == 0)
+		if (os_strcmp(key, dont_quote[i]) == 0)
 			return FALSE;
 		i++;
 	}
@@ -1213,28 +1131,30 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 		if (!strcmp(entry.key, "opensc_engine_path") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
+		    entry.type == DBUS_TYPE_STRING) {
 			os_free(opensc_engine_path);
 			opensc_engine_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
 			if (opensc_engine_path == NULL)
 				goto error;
 		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(pkcs11_engine_path);
 			pkcs11_engine_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
 			if (pkcs11_engine_path == NULL)
 				goto error;
 		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
-				 (entry.type == DBUS_TYPE_STRING)) {
+				 entry.type == DBUS_TYPE_STRING) {
 			os_free(pkcs11_module_path);
 			pkcs11_module_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
 			if (pkcs11_module_path == NULL)
 				goto error;
 		} else {
 			wpa_dbus_dict_entry_clear(&entry);
 			goto error;
 		}
-		wpa_dbus_dict_entry_clear(&entry);
 	}
 
 	os_free(wpa_s->conf->opensc_engine_path);
@@ -1305,8 +1225,8 @@
 		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
 					 DBUS_TYPE_INVALID);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
-			   "scanning state");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to return scanning state");
 	}
 
 	return reply;
@@ -1418,8 +1338,8 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
-	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
 	dbus_message_iter_recurse(&iter, &array);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
index 825bc6d..e60ad06 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -58,13 +58,13 @@
 					      struct wpa_ssid *ssid);
 
 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
-                                             struct wpa_supplicant *wpa_s);
+					     struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s);
+					  struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -76,7 +76,7 @@
 					   struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
-				        struct wpa_supplicant *wpa_s);
+					struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
 					   struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index 798eaef..5309a53 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -36,7 +36,7 @@
 				   DBUS_TYPE_INVALID))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
-	if (!os_strcmp(arg_bssid, "any"))
+	if (os_strcmp(arg_bssid, "any") == 0)
 		ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
 	else if (!hwaddr_aton(arg_bssid, bssid))
 		ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
@@ -46,10 +46,9 @@
 	}
 
 	if (ret < 0) {
-		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PBC_ERROR,
-					      "Could not start PBC "
-					      "negotiation");
+		return dbus_message_new_error(
+			message, WPAS_ERROR_WPS_PBC_ERROR,
+			"Could not start PBC negotiation");
 	}
 
 	return wpas_dbus_new_success_reply(message);
@@ -79,7 +78,7 @@
 				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
-	if (!os_strcmp(arg_bssid, "any"))
+	if (os_strcmp(arg_bssid, "any") == 0)
 		_bssid = NULL;
 	else if (!hwaddr_aton(arg_bssid, bssid))
 		_bssid = bssid;
@@ -145,7 +144,7 @@
 
 	if (ret < 0) {
 		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PBC_ERROR,
+					      WPAS_ERROR_WPS_REG_ERROR,
 					      "Could not request credentials");
 	}
 
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index fec174b..e9af6d9 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index 860b5a0..afb8c3b 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
 
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 142e1ab..47947c1 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index f6ef8f1..5f7b49d 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -16,7 +16,9 @@
       <command>wpa_gui</command>
       <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
       <arg>-i <replaceable>ifname</replaceable></arg>
+      <arg>-m <replaceable>seconds</replaceable></arg>
       <arg>-t</arg>
+      <arg>-q</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -51,12 +53,27 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-m seconds</term>
+
+	<listitem><para>Set the update interval in seconds for the signal
+	strength meter. This value must be a positive integer, otherwise
+	meter is not enabled (default behavior).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>-t</term>
 
         <listitem><para>Start program in the system tray only (if the window
 	manager supports it). By default the main status window is
 	shown.</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+	<term>-q</term>
+
+        <listitem><para>Run program in the quiet mode - do not display tray
+	icon pop-up messages.</para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
@@ -74,7 +91,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 3b4360b..b381e40 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,7 +62,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 9c114cc..d13a5db 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index e7bf4e0..46c21b5 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -736,7 +736,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2014,
+    <para>wpa_supplicant is copyright (c) 2003-2015,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index a92c5f7..ffee1f7 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - Internal driver interface wrappers
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -90,6 +90,10 @@
 static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
 			       struct wpa_driver_scan_params *params)
 {
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
+		return -EBUSY;
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (wpa_s->driver->scan2)
 		return wpa_s->driver->scan2(wpa_s->drv_priv, params);
 	return -1;
@@ -499,13 +503,6 @@
 					    proberesp, assocresp);
 }
 
-static inline int wpa_drv_shared_freq(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s->driver->shared_freq)
-		return -1;
-	return wpa_s->driver->shared_freq(wpa_s->drv_priv);
-}
-
 static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s,
 				  u8 *buf, size_t buf_len)
 {
@@ -565,12 +562,14 @@
 #endif /* ANDROID */
 
 static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
-					  const u8 *kek, const u8 *kck,
+					  const u8 *kek, size_t kek_len,
+					  const u8 *kck, size_t kck_len,
 					  const u8 *replay_ctr)
 {
 	if (!wpa_s->driver->set_rekey_info)
 		return;
-	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kek_len,
+				      kck, kck_len, replay_ctr);
 }
 
 static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
@@ -607,6 +606,27 @@
 	return wpa_s->driver->del_tx_ts(wpa_s->drv_priv, tid, address);
 }
 
+static inline int wpa_drv_tdls_enable_channel_switch(
+	struct wpa_supplicant *wpa_s, const u8 *addr, u8 oper_class,
+	const struct hostapd_freq_params *freq_params)
+{
+	if (!wpa_s->driver->tdls_enable_channel_switch)
+		return -1;
+	return wpa_s->driver->tdls_enable_channel_switch(wpa_s->drv_priv, addr,
+							 oper_class,
+							 freq_params);
+}
+
+static inline int
+wpa_drv_tdls_disable_channel_switch(struct wpa_supplicant *wpa_s,
+				    const u8 *addr)
+{
+	if (!wpa_s->driver->tdls_disable_channel_switch)
+		return -1;
+	return wpa_s->driver->tdls_disable_channel_switch(wpa_s->drv_priv,
+							  addr);
+}
+
 static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
 				   enum wnm_oper oper, const u8 *peer,
 				   u8 *buf, u16 *buf_len)
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index aa9ab50..9b7af30 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -480,6 +480,7 @@
 
 
 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+			       const char *altsubject[], int num_altsubject,
 			       const char *cert_hash,
 			       const struct wpabuf *cert)
 {
@@ -509,6 +510,14 @@
 			eapol_test_write_cert(e->server_cert_file,
 					      subject, cert);
 	}
+
+	if (altsubject) {
+		int i;
+
+		for (i = 0; i < num_altsubject; i++)
+			wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+				"depth=%d %s", depth, altsubject[i]);
+	}
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7fe92ea..d086624 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -71,6 +71,59 @@
 }
 
 
+/**
+ * wpas_reenabled_network_time - Time until first network is re-enabled
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: If all enabled networks are temporarily disabled, returns the time
+ *	(in sec) until the first network is re-enabled. Otherwise returns 0.
+ *
+ * This function is used in case all enabled networks are temporarily disabled,
+ * in which case it returns the time (in sec) that the first network will be
+ * re-enabled. The function assumes that at least one network is enabled.
+ */
+static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+	int disabled_for, res = 0;
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->auto_interworking && wpa_s->conf->interworking &&
+	    wpa_s->conf->cred)
+		return 0;
+#endif /* CONFIG_INTERWORKING */
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->disabled)
+			continue;
+
+		disabled_for = wpas_temp_disabled(wpa_s, ssid);
+		if (!disabled_for)
+			return 0;
+
+		if (!res || disabled_for < res)
+			res = disabled_for;
+	}
+
+	return res;
+}
+
+
+void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->disconnected || wpa_s->wpa_state != WPA_SCANNING)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Try to associate due to network getting re-enabled");
+	if (wpa_supplicant_fast_associate(wpa_s) != 1) {
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+}
+
+
 static struct wpa_bss * wpa_supplicant_get_new_bss(
 	struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
@@ -105,11 +158,32 @@
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_ssid *ssid, *old_ssid;
+	u8 drv_ssid[SSID_MAX_LEN];
+	size_t drv_ssid_len;
 	int res;
 
 	if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) {
 		wpa_supplicant_update_current_bss(wpa_s);
-		return 0;
+
+		if (wpa_s->current_ssid->ssid_len == 0)
+			return 0; /* current profile still in use */
+		res = wpa_drv_get_ssid(wpa_s, drv_ssid);
+		if (res < 0) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Failed to read SSID from driver");
+			return 0; /* try to use current profile */
+		}
+		drv_ssid_len = res;
+
+		if (drv_ssid_len == wpa_s->current_ssid->ssid_len &&
+		    os_memcmp(drv_ssid, wpa_s->current_ssid->ssid,
+			      drv_ssid_len) == 0)
+			return 0; /* current profile still in use */
+
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Driver-initiated BSS selection changed the SSID to %s",
+			wpa_ssid_txt(drv_ssid, drv_ssid_len));
+		/* continue selecting a new network profile */
 	}
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
@@ -175,6 +249,15 @@
 		wpa_s->countermeasures = 0;
 		wpa_drv_set_countermeasures(wpa_s, 0);
 		wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
+
+		/*
+		 * It is possible that the device is sched scanning, which means
+		 * that a connection attempt will be done only when we receive
+		 * scan results. However, in this case, it would be preferable
+		 * to scan and connect immediately, so cancel the sched_scan and
+		 * issue a regular scan flow.
+		 */
+		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
 }
@@ -240,7 +323,7 @@
 						    ie.pmkid + i * PMKID_LEN,
 						    NULL, NULL, 0);
 		if (pmksa_set == 0) {
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 			break;
 		}
 	}
@@ -476,8 +559,7 @@
 
 #ifdef CONFIG_IEEE80211W
 		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-		    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-		     wpa_s->conf->pmf : ssid->ieee80211w) ==
+		    wpas_get_ssid_pmf(wpa_s, ssid) ==
 		    MGMT_FRAME_PROTECTION_REQUIRED) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
 				"frame protection");
@@ -670,9 +752,10 @@
 				 * order to join a BSS all required rates
 				 * have to be supported by the hardware.
 				 */
-				wpa_dbg(wpa_s, MSG_DEBUG, "   hardware does "
-					"not support required rate %d.%d Mbps",
-					r / 10, r % 10);
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
+					r / 10, r % 10,
+					bss->freq, mode->mode, mode->num_rates);
 				return 0;
 			}
 		}
@@ -698,6 +781,33 @@
 }
 
 
+static int match_mac_mask(const u8 *addr_a, const u8 *addr_b, const u8 *mask)
+{
+	size_t i;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((addr_a[i] & mask[i]) != (addr_b[i] & mask[i]))
+			return 0;
+	}
+	return 1;
+}
+
+
+static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
+{
+	size_t i;
+
+	for (i = 0; i < num; i++) {
+		const u8 *a = list + i * ETH_ALEN * 2;
+		const u8 *m = a + ETH_ALEN;
+
+		if (match_mac_mask(a, addr, m))
+			return 1;
+	}
+	return 0;
+}
+
+
 static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 					    int i, struct wpa_bss *bss,
 					    struct wpa_ssid *group,
@@ -822,6 +932,24 @@
 			continue;
 		}
 
+		/* check blacklist */
+		if (ssid->num_bssid_blacklist &&
+		    addr_in_list(bss->bssid, ssid->bssid_blacklist,
+				 ssid->num_bssid_blacklist)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - BSSID blacklisted");
+			continue;
+		}
+
+		/* if there is a whitelist, only accept those APs */
+		if (ssid->num_bssid_whitelist &&
+		    !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+				  ssid->num_bssid_whitelist)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - BSSID not in whitelist");
+			continue;
+		}
+
 		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
 			continue;
 
@@ -957,14 +1085,13 @@
 	struct wpa_bss *selected = NULL;
 	int prio;
 	struct wpa_ssid *next_ssid = NULL;
+	struct wpa_ssid *ssid;
 
 	if (wpa_s->last_scan_res == NULL ||
 	    wpa_s->last_scan_res_used == 0)
 		return NULL; /* no scan results from last update */
 
 	if (wpa_s->next_ssid) {
-		struct wpa_ssid *ssid;
-
 		/* check that next_ssid is still valid */
 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
 			if (ssid == wpa_s->next_ssid)
@@ -1000,6 +1127,27 @@
 			break;
 	}
 
+	ssid = *selected_ssid;
+	if (selected && ssid && ssid->mem_only_psk && !ssid->psk_set &&
+	    !ssid->passphrase && !ssid->ext_psk) {
+		const char *field_name, *txt = NULL;
+
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"PSK/passphrase not yet available for the selected network");
+
+		wpas_notify_network_request(wpa_s, ssid,
+					    WPA_CTRL_REQ_PSK_PASSPHRASE, NULL);
+
+		field_name = wpa_supplicant_ctrl_req_to_string(
+			WPA_CTRL_REQ_PSK_PASSPHRASE, NULL, &txt);
+		if (field_name == NULL)
+			return NULL;
+
+		wpas_send_ctrl_req(wpa_s, ssid, field_name, txt);
+
+		selected = NULL;
+	}
+
 	return selected;
 }
 
@@ -1138,7 +1286,9 @@
 				       struct wpa_ssid *ssid)
 {
 	struct wpa_bss *current_bss = NULL;
+#ifndef CONFIG_NO_ROAMING
 	int min_diff;
+#endif /* CONFIG_NO_ROAMING */
 
 	if (wpa_s->reassociate)
 		return 1; /* explicit request to reassociate */
@@ -1170,10 +1320,14 @@
 
 #ifndef CONFIG_NO_ROAMING
 	wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
-	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
-		MAC2STR(current_bss->bssid), current_bss->level);
-	wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
-		MAC2STR(selected->bssid), selected->level);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
+		" level=%d snr=%d est_throughput=%u",
+		MAC2STR(current_bss->bssid), current_bss->level,
+		current_bss->snr, current_bss->est_throughput);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR
+		" level=%d snr=%d est_throughput=%u",
+		MAC2STR(selected->bssid), selected->level,
+		selected->snr, selected->est_throughput);
 
 	if (wpa_s->current_ssid->bssid_set &&
 	    os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
@@ -1183,6 +1337,12 @@
 		return 1;
 	}
 
+	if (selected->est_throughput > current_bss->est_throughput + 5000) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Allow reassociation - selected BSS has better estimated throughput");
+		return 1;
+	}
+
 	if (current_bss->level < 0 && current_bss->level > selected->level) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
 			"signal level");
@@ -1268,7 +1428,7 @@
 #endif /* CONFIG_NO_RANDOM_POOL */
 
 	if (own_request && wpa_s->scan_res_handler &&
-	    (wpa_s->own_scan_running || !wpa_s->external_scan_running)) {
+	    (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
 		void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
 					 struct wpa_scan_results *scan_res);
 
@@ -1289,7 +1449,7 @@
 	}
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
-		wpa_s->own_scan_running, wpa_s->external_scan_running);
+		wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
 	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
 	    wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
 		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
@@ -1302,7 +1462,7 @@
 
 	wpas_notify_scan_done(wpa_s, 1);
 
-	if (!wpa_s->own_scan_running && wpa_s->external_scan_running) {
+	if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
 		wpa_scan_results_free(scan_res);
 		return 0;
@@ -1357,6 +1517,20 @@
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
+	int time_to_reenable = wpas_reenabled_network_time(wpa_s);
+
+	if (time_to_reenable > 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Postpone network selection by %d seconds since all networks are disabled",
+			time_to_reenable);
+		eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+		eloop_register_timeout(time_to_reenable, 0,
+				       wpas_network_reenabled, wpa_s, NULL);
+		return 0;
+	}
+
+	if (wpa_s->p2p_mgmt)
+		return 0; /* no normal connection on p2p_mgmt interface */
 
 	selected = wpa_supplicant_pick_network(wpa_s, &ssid);
 
@@ -1404,7 +1578,12 @@
 			int timeout_sec = wpa_s->scan_interval;
 			int timeout_usec = 0;
 #ifdef CONFIG_P2P
-			if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+			int res;
+
+			res = wpas_p2p_scan_no_go_seen(wpa_s);
+			if (res == 2)
+				return 2;
+			if (res == 1)
 				return 0;
 
 			if (wpa_s->p2p_in_provisioning ||
@@ -1454,12 +1633,21 @@
 }
 
 
-static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
-					      union wpa_event_data *data)
+static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+					     union wpa_event_data *data)
 {
 	struct wpa_supplicant *ifs;
+	int res;
 
-	if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
+	res = _wpa_supplicant_event_scan_results(wpa_s, data, 1);
+	if (res == 2) {
+		/*
+		 * Interface may have been removed, so must not dereference
+		 * wpa_s after this.
+		 */
+		return 1;
+	}
+	if (res != 0) {
 		/*
 		 * If no scan results could be fetched, then no need to
 		 * notify those interfaces that did not actually request
@@ -1467,7 +1655,7 @@
 		 * interface, do not notify other interfaces to avoid concurrent
 		 * operations during a connection attempt.
 		 */
-		return;
+		return 0;
 	}
 
 	/*
@@ -1482,6 +1670,8 @@
 			_wpa_supplicant_event_scan_results(ifs, data, 0);
 		}
 	}
+
+	return 0;
 }
 
 #endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -1863,6 +2053,8 @@
 	}
 #endif /* CONFIG_AP */
 
+	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+
 	ft_completed = wpa_ft_is_completed(wpa_s->wpa);
 	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
 		return;
@@ -2040,6 +2232,9 @@
 		wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies,
 				    data->assoc_info.resp_ies_len,
 				    &data->assoc_info.wmm_params);
+
+		if (wpa_s->reassoc_same_bss)
+			wmm_ac_restore_tspecs(wpa_s);
 	}
 }
 
@@ -2128,8 +2323,6 @@
 		return;
 	}
 
-	wmm_ac_notify_disassoc(wpa_s);
-
 	if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
 		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
 			"pre-shared key may be incorrect");
@@ -2411,6 +2604,10 @@
 			wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN,
 					  data->tdls.peer);
 		break;
+	case TDLS_REQUEST_DISCOVER:
+			wpa_tdls_send_discovery_request(wpa_s->wpa,
+							data->tdls.peer);
+		break;
 	}
 }
 #endif /* CONFIG_TDLS */
@@ -2588,6 +2785,9 @@
 	}
 #endif /* CONFIG_AP */
 
+	if (!locally_generated)
+		wpa_s->own_disconnect_req = 0;
+
 	wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
 
 	if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
@@ -2773,6 +2973,14 @@
 				ifs, &ifs->hw.num_modes, &ifs->hw.flags);
 		}
 	}
+
+	/* Restart sched_scan with updated channel list */
+	if (wpa_s->sched_scanning) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Channel list changed restart sched scan.");
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
 }
 
 
@@ -2946,7 +3154,9 @@
 	}
 	wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
 	wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
-			       data->assoc_info.ptk_kek);
+			       data->assoc_info.ptk_kck_len,
+			       data->assoc_info.ptk_kek,
+			       data->assoc_info.ptk_kek_len);
 }
 
 
@@ -2954,6 +3164,7 @@
 			  union wpa_event_data *data)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	int resched;
 
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
 	    event != EVENT_INTERFACE_ENABLED &&
@@ -3027,7 +3238,7 @@
 			}
 		} else {
 			wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
-			wpa_s->external_scan_running = 1;
+			wpa_s->radio->external_scan_running = 1;
 			wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
 		}
 		break;
@@ -3041,9 +3252,10 @@
 			wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
 				diff.sec, diff.usec);
 		}
-		wpa_supplicant_event_scan_results(wpa_s, data);
+		if (wpa_supplicant_event_scan_results(wpa_s, data))
+			break; /* interface may have been removed */
 		wpa_s->own_scan_running = 0;
-		wpa_s->external_scan_running = 0;
+		wpa_s->radio->external_scan_running = 0;
 		radio_work_check_next(wpa_s);
 		break;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3214,6 +3426,29 @@
 				  data->ch_switch.cf1,
 				  data->ch_switch.cf2);
 		break;
+#ifdef NEED_AP_MLME
+	case EVENT_DFS_RADAR_DETECTED:
+		if (data)
+			wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_STARTED:
+		if (data)
+			wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_FINISHED:
+		if (data)
+			wpas_event_dfs_cac_finished(wpa_s, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_ABORTED:
+		if (data)
+			wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
+		break;
+	case EVENT_DFS_NOP_FINISHED:
+		if (data)
+			wpas_event_dfs_cac_nop_finished(wpa_s,
+							&data->dfs_event);
+		break;
+#endif /* NEED_AP_MLME */
 #endif /* CONFIG_AP */
 	case EVENT_RX_MGMT: {
 		u16 fc, stype;
@@ -3358,6 +3593,8 @@
 			data->signal_change.current_signal,
 			data->signal_change.current_noise,
 			data->signal_change.current_txrate);
+		wpa_bss_update_level(wpa_s->current_bss,
+				     data->signal_change.current_signal);
 		bgscan_notify_signal_change(
 			wpa_s, data->signal_change.above_threshold,
 			data->signal_change.current_signal,
@@ -3378,6 +3615,7 @@
 			if (!wpa_s->ap_iface) {
 				wpa_supplicant_set_state(wpa_s,
 							 WPA_DISCONNECTED);
+				wpa_s->scan_req = NORMAL_SCAN_REQ;
 				wpa_supplicant_req_scan(wpa_s, 0, 0);
 			} else
 				wpa_supplicant_set_state(wpa_s,
@@ -3395,11 +3633,24 @@
 		    (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group &&
 		     wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) {
 			/*
+			 * Mark interface disabled if this happens to end up not
+			 * being removed as a separate P2P group interface.
+			 */
+			wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+			/*
 			 * The interface was externally disabled. Remove
 			 * it assuming an external entity will start a
 			 * new session if needed.
 			 */
-			wpas_p2p_disconnect(wpa_s);
+			if (wpa_s->current_ssid &&
+			    wpa_s->current_ssid->p2p_group)
+				wpas_p2p_interface_unavailable(wpa_s);
+			else
+				wpas_p2p_disconnect(wpa_s);
+			/*
+			 * wpa_s instance may have been freed, so must not use
+			 * it here anymore.
+			 */
 			break;
 		}
 		if (wpa_s->p2p_scan_work && wpa_s->global->p2p &&
@@ -3480,6 +3731,7 @@
 	case EVENT_SCHED_SCAN_STOPPED:
 		wpa_s->pno = 0;
 		wpa_s->sched_scanning = 0;
+		resched = wpa_s->scanning;
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
@@ -3494,6 +3746,8 @@
 		} else if (wpa_s->pno_sched_pending) {
 			wpa_s->pno_sched_pending = 0;
 			wpas_start_pno(wpa_s);
+		} else if (resched) {
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
 
 		break;
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 9eb5064..98af530 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -7,6 +7,7 @@
  */
 
 #include "includes.h"
+#include <sys/stat.h>
 
 #include "common.h"
 #include "eloop.h"
@@ -45,7 +46,7 @@
 
 struct osu_provider {
 	u8 bssid[ETH_ALEN];
-	u8 osu_ssid[32];
+	u8 osu_ssid[SSID_MAX_LEN];
 	u8 osu_ssid_len;
 	char server_uri[256];
 	u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
@@ -216,6 +217,30 @@
 }
 
 
+static void hs20_set_osu_access_permission(const char *osu_dir,
+					   const char *fname)
+{
+	struct stat statbuf;
+
+	/* Get OSU directory information */
+	if (stat(osu_dir, &statbuf) < 0) {
+		wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
+			   osu_dir);
+		return;
+	}
+
+	if (chmod(fname, statbuf.st_mode) < 0) {
+		wpa_printf(MSG_WARNING,
+			   "Cannot change the permissions for %s", fname);
+		return;
+	}
+
+	if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+		wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
+			   fname);
+	}
+}
+
 static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
 					 const u8 *sa, const u8 *pos,
 					 size_t slen)
@@ -278,6 +303,9 @@
 	f = fopen(fname, "wb");
 	if (f == NULL)
 		return -1;
+
+	hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
 	if (fwrite(pos, slen, 1, f) != 1) {
 		fclose(f);
 		unlink(fname);
@@ -327,11 +355,11 @@
 
 
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
-				  const u8 *sa, const u8 *data, size_t slen)
+				  struct wpa_bss *bss, const u8 *sa,
+				  const u8 *data, size_t slen)
 {
 	const u8 *pos = data;
 	u8 subtype;
-	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
 	struct wpa_bss_anqp *anqp = NULL;
 	int ret;
 
@@ -352,6 +380,11 @@
 		wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
 			" HS Capability List", MAC2STR(sa));
 		wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->hs20_capability_list);
+			anqp->hs20_capability_list =
+				wpabuf_alloc_copy(pos, slen);
+		}
 		break;
 	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
 		wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
@@ -479,6 +512,9 @@
 		hs20_free_osu_prov(wpa_s);
 		return;
 	}
+
+	hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
 	for (i = 0; i < wpa_s->osu_prov_count; i++) {
 		struct osu_provider *osu = &wpa_s->osu_prov[i];
 		if (i > 0)
@@ -786,7 +822,7 @@
 			continue;
 		}
 		osu_ssid_len = *pos++;
-		if (osu_ssid_len > 32) {
+		if (osu_ssid_len > SSID_MAX_LEN) {
 			wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID "
 				   "Length %u", osu_ssid_len);
 			continue;
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 06739f5..85b5120 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -17,7 +17,8 @@
 void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
 		       struct wpabuf *buf);
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
-				  const u8 *sa, const u8 *data, size_t slen);
+				  struct wpa_bss *bss, const u8 *sa,
+				  const u8 *data, size_t slen);
 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 		    struct wpa_bss *bss);
 int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 116df05..4a39665 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -73,17 +73,23 @@
 
 static void interworking_reconnect(struct wpa_supplicant *wpa_s)
 {
+	unsigned int tried;
+
 	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
 		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	}
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
+	tried = wpa_s->interworking_fast_assoc_tried;
+	wpa_s->interworking_fast_assoc_tried = 1;
 
-	if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+	if (!tried && wpa_supplicant_fast_associate(wpa_s) >= 0)
 		return;
 
+	wpa_s->interworking_fast_assoc_tried = 0;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
@@ -245,8 +251,8 @@
 	struct wpabuf *extra = NULL;
 	int all = wpa_s->fetch_all_anqp;
 
-	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
-		   MAC2STR(bss->bssid));
+	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+		MAC2STR(bss->bssid));
 	wpa_s->interworking_gas_bss = bss;
 
 	info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
@@ -307,14 +313,14 @@
 	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
 			    interworking_anqp_resp_cb, wpa_s);
 	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
 		wpabuf_free(buf);
 		ret = -1;
 		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
 				       NULL);
 	} else
-		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
-			   "%u", res);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"ANQP: Query started with dialog token %u", res);
 
 	return ret;
 }
@@ -582,56 +588,69 @@
 }
 
 
-static int nai_realm_cred_username(struct nai_realm_eap *eap)
+static int nai_realm_cred_username(struct wpa_supplicant *wpa_s,
+				   struct nai_realm_eap *eap)
 {
-	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-cred-username: EAP method not supported: %d",
+			eap->method);
 		return 0; /* method not supported */
+	}
 
 	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
 	    eap->method != EAP_TYPE_FAST) {
 		/* Only tunneled methods with username/password supported */
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-cred-username: Method: %d is not TTLS, PEAP, or FAST",
+			eap->method);
 		return 0;
 	}
 
 	if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
 		if (eap->inner_method &&
-		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"nai-realm-cred-username: PEAP/FAST: Inner method not supported: %d",
+				eap->inner_method);
 			return 0;
+		}
 		if (!eap->inner_method &&
-		    eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+		    eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"nai-realm-cred-username: MSCHAPv2 not supported");
 			return 0;
+		}
 	}
 
 	if (eap->method == EAP_TYPE_TTLS) {
 		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
 			return 1; /* Assume TTLS/MSCHAPv2 is used */
 		if (eap->inner_method &&
-		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"nai-realm-cred-username: TTLS, but inner not supported: %d",
+				eap->inner_method);
 			return 0;
+		}
 		if (eap->inner_non_eap &&
 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
 		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
-		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"nai-realm-cred-username: TTLS, inner-non-eap not supported: %d",
+				eap->inner_non_eap);
 			return 0;
+		}
 	}
 
 	if (eap->inner_method &&
 	    eap->inner_method != EAP_TYPE_GTC &&
-	    eap->inner_method != EAP_TYPE_MSCHAPV2)
-		return 0;
-
-	return 1;
-}
-
-
-static int nai_realm_cred_cert(struct nai_realm_eap *eap)
-{
-	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
-		return 0; /* method not supported */
-
-	if (eap->method != EAP_TYPE_TLS) {
-		/* Only EAP-TLS supported for credential authentication */
+	    eap->inner_method != EAP_TYPE_MSCHAPV2) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-cred-username: inner-method not GTC or MSCHAPv2: %d",
+			eap->inner_method);
 		return 0;
 	}
 
@@ -639,27 +658,55 @@
 }
 
 
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
+static int nai_realm_cred_cert(struct wpa_supplicant *wpa_s,
+			       struct nai_realm_eap *eap)
+{
+	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-cred-cert: Method not supported: %d",
+			eap->method);
+		return 0; /* method not supported */
+	}
+
+	if (eap->method != EAP_TYPE_TLS) {
+		/* Only EAP-TLS supported for credential authentication */
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-cred-cert: Method not TLS: %d",
+			eap->method);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+						 struct wpa_cred *cred,
 						 struct nai_realm *realm)
 {
 	u8 e;
 
-	if (cred == NULL ||
-	    cred->username == NULL ||
+	if (cred->username == NULL ||
 	    cred->username[0] == '\0' ||
 	    ((cred->password == NULL ||
 	      cred->password[0] == '\0') &&
 	     (cred->private_key == NULL ||
-	      cred->private_key[0] == '\0')))
+	      cred->private_key[0] == '\0'))) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"nai-realm-find-eap: incomplete cred info: username: %s  password: %s private_key: %s",
+			cred->username ? cred->username : "NULL",
+			cred->password ? cred->password : "NULL",
+			cred->private_key ? cred->private_key : "NULL");
 		return NULL;
+	}
 
 	for (e = 0; e < realm->eap_count; e++) {
 		struct nai_realm_eap *eap = &realm->eap[e];
 		if (cred->password && cred->password[0] &&
-		    nai_realm_cred_username(eap))
+		    nai_realm_cred_username(wpa_s, eap))
 			return eap;
 		if (cred->private_key && cred->private_key[0] &&
-		    nai_realm_cred_cert(eap))
+		    nai_realm_cred_cert(wpa_s, eap))
 			return eap;
 	}
 
@@ -869,6 +916,7 @@
 	if (ssid == wpa_s->current_ssid) {
 		wpa_sm_set_config(wpa_s->wpa, NULL);
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	}
@@ -909,7 +957,7 @@
 
 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
 				     struct wpa_cred *cred,
-				     struct wpa_bss *bss)
+				     struct wpa_bss *bss, int only_add)
 {
 #ifdef INTERWORKING_3GPP
 	struct wpa_ssid *ssid;
@@ -920,13 +968,13 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
-		   MAC2STR(bss->bssid));
+	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+		" (3GPP)", MAC2STR(bss->bssid));
 
 	if (already_connected(wpa_s, cred, bss)) {
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
 			MAC2STR(bss->bssid));
-		return 0;
+		return wpa_s->current_ssid->id;
 	}
 
 	remove_duplicate_network(wpa_s, cred, bss);
@@ -978,13 +1026,13 @@
 		break;
 	}
 	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
-			   eap_type);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Selected EAP method (%d) not supported", eap_type);
 		goto fail;
 	}
 
 	if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
-		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
+		wpa_msg(wpa_s, MSG_DEBUG, "Failed to set Root NAI");
 		goto fail;
 	}
 
@@ -1003,9 +1051,10 @@
 
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
-	interworking_reconnect(wpa_s);
+	if (!only_add)
+		interworking_reconnect(wpa_s);
 
-	return 0;
+	return ssid->id;
 
 fail:
 	wpas_notify_network_removed(wpa_s, ssid);
@@ -1453,17 +1502,17 @@
 
 static int interworking_connect_roaming_consortium(
 	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
-	struct wpa_bss *bss)
+	struct wpa_bss *bss, int only_add)
 {
 	struct wpa_ssid *ssid;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
-		   "roaming consortium match", MAC2STR(bss->bssid));
+	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+		" based on roaming consortium match", MAC2STR(bss->bssid));
 
 	if (already_connected(wpa_s, cred, bss)) {
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
 			MAC2STR(bss->bssid));
-		return 0;
+		return wpa_s->current_ssid->id;
 	}
 
 	remove_duplicate_network(wpa_s, cred, bss);
@@ -1486,8 +1535,8 @@
 		goto fail;
 
 	if (cred->eap_method == NULL) {
-		wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
-			   "credential using roaming consortium");
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: No EAP method set for credential using roaming consortium");
 		goto fail;
 	}
 
@@ -1499,9 +1548,10 @@
 
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
-	interworking_reconnect(wpa_s);
+	if (!only_add)
+		interworking_reconnect(wpa_s);
 
-	return 0;
+	return ssid->id;
 
 fail:
 	wpas_notify_network_removed(wpa_s, ssid);
@@ -1511,7 +1561,8 @@
 
 
 static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
-				       struct wpa_bss *bss, int allow_excluded)
+				       struct wpa_bss *bss, int allow_excluded,
+				       int only_add)
 {
 	struct wpa_cred *cred, *cred_rc, *cred_3gpp;
 	struct wpa_ssid *ssid;
@@ -1526,8 +1577,9 @@
 		return -1;
 	if (disallowed_bssid(wpa_s, bss->bssid) ||
 	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
-		wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
-			   MACSTR, MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Reject connection to disallowed BSS "
+			MACSTR, MAC2STR(bss->bssid));
 		return -1;
 	}
 
@@ -1540,27 +1592,26 @@
 		 * 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");
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Network does not use RSN");
 		return -1;
 	}
 
 	cred_rc = interworking_credentials_available_roaming_consortium(
 		wpa_s, bss, 0, excl);
 	if (cred_rc) {
-		wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
-			   "consortium matching credential priority %d "
-			   "sp_priority %d",
-			   cred_rc->priority, cred_rc->sp_priority);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
+			cred_rc->priority, cred_rc->sp_priority);
 		if (allow_excluded && excl && !(*excl))
 			excl = NULL;
 	}
 
 	cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl);
 	if (cred) {
-		wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
-			   "matching credential priority %d sp_priority %d",
-			   cred->priority, cred->sp_priority);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
+			cred->priority, cred->sp_priority);
 		if (allow_excluded && excl && !(*excl))
 			excl = NULL;
 	}
@@ -1568,22 +1619,22 @@
 	cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0,
 							    excl);
 	if (cred_3gpp) {
-		wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
-			   "credential priority %d sp_priority %d",
-			   cred_3gpp->priority, cred_3gpp->sp_priority);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
+			cred_3gpp->priority, cred_3gpp->sp_priority);
 		if (allow_excluded && excl && !(*excl))
 			excl = NULL;
 	}
 
 	if (!cred_rc && !cred && !cred_3gpp) {
-		wpa_printf(MSG_DEBUG, "Interworking: No full credential matches - consider options without BW(etc.) limits");
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: No full credential matches - consider options without BW(etc.) limits");
 		cred_rc = interworking_credentials_available_roaming_consortium(
 			wpa_s, bss, 1, excl);
 		if (cred_rc) {
-			wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
-				   "consortium matching credential priority %d "
-				   "sp_priority %d (ignore BW)",
-				   cred_rc->priority, cred_rc->sp_priority);
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
+				cred_rc->priority, cred_rc->sp_priority);
 			if (allow_excluded && excl && !(*excl))
 				excl = NULL;
 		}
@@ -1591,10 +1642,9 @@
 		cred = interworking_credentials_available_realm(wpa_s, bss, 1,
 								excl);
 		if (cred) {
-			wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm "
-				   "list matching credential priority %d "
-				   "sp_priority %d (ignore BW)",
-				   cred->priority, cred->sp_priority);
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
+				cred->priority, cred->sp_priority);
 			if (allow_excluded && excl && !(*excl))
 				excl = NULL;
 		}
@@ -1602,10 +1652,9 @@
 		cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss,
 								    1, excl);
 		if (cred_3gpp) {
-			wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP "
-				   "matching credential priority %d "
-				   "sp_priority %d (ignore BW)",
-				   cred_3gpp->priority, cred_3gpp->sp_priority);
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
+				cred_3gpp->priority, cred_3gpp->sp_priority);
 			if (allow_excluded && excl && !(*excl))
 				excl = NULL;
 		}
@@ -1615,45 +1664,48 @@
 	    (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) &&
 	    (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
 		return interworking_connect_roaming_consortium(wpa_s, cred_rc,
-							       bss);
+							       bss, only_add);
 
 	if (cred_3gpp &&
 	    (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) {
-		return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+		return interworking_connect_3gpp(wpa_s, cred_3gpp, bss,
+						 only_add);
 	}
 
 	if (cred == NULL) {
-		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
-			   "found for " MACSTR, MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: No matching credentials found for "
+			MACSTR, MAC2STR(bss->bssid));
 		return -1;
 	}
 
 	realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
 				&count);
 	if (realm == NULL) {
-		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
-			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Could not parse NAI Realm list from "
+			MACSTR, MAC2STR(bss->bssid));
 		return -1;
 	}
 
 	for (i = 0; i < count; i++) {
 		if (!nai_realm_match(&realm[i], cred->realm))
 			continue;
-		eap = nai_realm_find_eap(cred, &realm[i]);
+		eap = nai_realm_find_eap(wpa_s, cred, &realm[i]);
 		if (eap)
 			break;
 	}
 
 	if (!eap) {
-		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
-			   "and EAP method found for " MACSTR,
-			   MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: No matching credentials and EAP method found for "
+			MACSTR, MAC2STR(bss->bssid));
 		nai_realm_free(realm, count);
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
-		   MAC2STR(bss->bssid));
+	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR,
+		MAC2STR(bss->bssid));
 
 	if (already_connected(wpa_s, cred, bss)) {
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
@@ -1755,9 +1807,10 @@
 
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
-	interworking_reconnect(wpa_s);
+	if (!only_add)
+		interworking_reconnect(wpa_s);
 
-	return 0;
+	return ssid->id;
 
 fail:
 	wpas_notify_network_removed(wpa_s, ssid);
@@ -1767,9 +1820,10 @@
 }
 
 
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			 int only_add)
 {
-	return interworking_connect_helper(wpa_s, bss, 1);
+	return interworking_connect_helper(wpa_s, bss, 1, only_add);
 }
 
 
@@ -1808,22 +1862,29 @@
 	int ret;
 	int is_excluded = 0;
 
-	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"interworking-avail-3gpp: not avail, anqp: %p  anqp_3gpp: %p",
+			bss->anqp, bss->anqp ? bss->anqp->anqp_3gpp : NULL);
 		return NULL;
+	}
 
 #ifdef CONFIG_EAP_PROXY
 	if (!wpa_s->imsi[0]) {
 		size_t len;
-		wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: IMSI not available - try to read again through eap_proxy");
 		wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
 							     wpa_s->imsi,
 							     &len);
 		if (wpa_s->mnc_len > 0) {
 			wpa_s->imsi[len] = '\0';
-			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
-				   wpa_s->imsi, wpa_s->mnc_len);
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"eap_proxy: IMSI %s (MNC length %d)",
+				wpa_s->imsi, wpa_s->mnc_len);
 		} else {
-			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"eap_proxy: IMSI not available");
 		}
 	}
 #endif /* CONFIG_EAP_PROXY */
@@ -1874,10 +1935,12 @@
 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
 	compare:
 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
-		wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
-			   MACSTR, MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Parsing 3GPP info from " MACSTR,
+			MAC2STR(bss->bssid));
 		ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
-		wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+		wpa_msg(wpa_s, MSG_DEBUG, "PLMN match %sfound",
+			ret ? "" : "not ");
 		if (ret) {
 			if (cred_no_required_oi_match(cred, bss))
 				continue;
@@ -1929,12 +1992,13 @@
 	if (wpa_s->conf->cred == NULL)
 		return NULL;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
-		   MACSTR, MAC2STR(bss->bssid));
+	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+		MACSTR, MAC2STR(bss->bssid));
 	realm = nai_realm_parse(bss->anqp->nai_realm, &count);
 	if (realm == NULL) {
-		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
-			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Could not parse NAI Realm list from "
+			MACSTR, MAC2STR(bss->bssid));
 		return NULL;
 	}
 
@@ -1945,7 +2009,7 @@
 		for (i = 0; i < count; i++) {
 			if (!nai_realm_match(&realm[i], cred->realm))
 				continue;
-			if (nai_realm_find_eap(cred, &realm[i])) {
+			if (nai_realm_find_eap(wpa_s, cred, &realm[i])) {
 				if (cred_no_required_oi_match(cred, bss))
 					continue;
 				if (!ignore_bw &&
@@ -1973,6 +2037,9 @@
 					}
 				}
 				break;
+			} else {
+				wpa_msg(wpa_s, MSG_DEBUG,
+					"Interworking: realm-find-eap returned false");
 			}
 		}
 	}
@@ -2113,8 +2180,9 @@
 		realm = os_strchr(nai, '@');
 		if (realm)
 			realm++;
-		wpa_printf(MSG_DEBUG, "Interworking: Search for match "
-			   "with SIM/USIM domain %s", realm);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Search for match with SIM/USIM domain %s",
+			realm);
 		if (realm &&
 		    domain_name_list_contains(domain_names, realm, 1))
 			return 1;
@@ -2127,8 +2195,9 @@
 		return ret;
 
 	for (i = 0; i < cred->num_domain; i++) {
-		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
-			   "home SP FQDN %s", cred->domain[i]);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Search for match with home SP FQDN %s",
+			cred->domain[i]);
 		if (domain_name_list_contains(domain_names, cred->domain[i], 1))
 			return 1;
 	}
@@ -2304,14 +2373,16 @@
 							  &excluded);
 		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));
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Credential match with " MACSTR
+				" but network does not use RSN",
+				MAC2STR(bss->bssid));
 			continue;
 		}
 		if (!excluded)
@@ -2402,8 +2473,8 @@
 		 * have matching APs.
 		 */
 		if (interworking_find_network_match(wpa_s)) {
-			wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
-				   "match for enabled network configurations");
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Possible BSS match for enabled network configurations");
 			if (wpa_s->auto_select) {
 				interworking_reconnect(wpa_s);
 				return;
@@ -2411,8 +2482,8 @@
 		}
 
 		if (wpa_s->auto_network_select) {
-			wpa_printf(MSG_DEBUG, "Interworking: Continue "
-				   "scanning after ANQP fetch");
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Continue scanning after ANQP fetch");
 			wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
 						0);
 			return;
@@ -2420,6 +2491,8 @@
 
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
 			"with matching credentials found");
+		if (wpa_s->wpa_state == WPA_SCANNING)
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 	}
 
 	if (selected) {
@@ -2432,7 +2505,7 @@
 			   MAC2STR(selected->bssid));
 		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
 			MAC2STR(selected->bssid));
-		interworking_connect(wpa_s, selected);
+		interworking_connect(wpa_s, selected, 0);
 	}
 }
 
@@ -2463,9 +2536,10 @@
 		    os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
 			continue;
 
-		wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
-			   "already fetched BSSID " MACSTR " and " MACSTR,
-			   MAC2STR(other->bssid), MAC2STR(bss->bssid));
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Share ANQP data with already fetched BSSID "
+			MACSTR " and " MACSTR,
+			MAC2STR(other->bssid), MAC2STR(bss->bssid));
 		other->anqp->users++;
 		return other->anqp;
 	}
@@ -2556,7 +2630,12 @@
 		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
 
 	wpa_s->fetch_anqp_in_progress = 1;
-	interworking_next_anqp_fetch(wpa_s);
+
+	/*
+	 * Start actual ANQP operation from eloop call to make sure the loop
+	 * does not end up using excessive recursion.
+	 */
+	eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL);
 }
 
 
@@ -2603,8 +2682,9 @@
 	if (freq <= 0)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
-		   MAC2STR(dst), (unsigned int) num_ids);
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"ANQP: Query Request to " MACSTR " for %u id(s)",
+		MAC2STR(dst), (unsigned int) num_ids);
 
 #ifdef CONFIG_HS20
 	if (subtypes != 0) {
@@ -2622,12 +2702,13 @@
 
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
 		wpabuf_free(buf);
 		ret = -1;
-	} else
-		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
-			   "%u", res);
+	} else {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"ANQP: Query started with dialog token %u", res);
+	}
 
 	return ret;
 }
@@ -2651,6 +2732,12 @@
 	case ANQP_CAPABILITY_LIST:
 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
 			" ANQP Capability list", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
+				  pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->capability_list);
+			anqp->capability_list = wpabuf_alloc_copy(pos, slen);
+		}
 		break;
 	case ANQP_VENUE_NAME:
 		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@@ -2739,26 +2826,27 @@
 
 			switch (type) {
 			case HS20_ANQP_OUI_TYPE:
-				hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
-							     slen);
+				hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
+							     pos, slen);
 				break;
 			default:
-				wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
-					   "vendor type %u", type);
+				wpa_msg(wpa_s, MSG_DEBUG,
+					"HS20: Unsupported ANQP vendor type %u",
+					type);
 				break;
 			}
 			break;
 #endif /* CONFIG_HS20 */
 		default:
-			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
-				   "vendor-specific ANQP OUI %06x",
-				   WPA_GET_BE24(pos));
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Interworking: Unsupported vendor-specific ANQP OUI %06x",
+				WPA_GET_BE24(pos));
 			return;
 		}
 		break;
 	default:
-		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
-			   "%u", info_id);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Interworking: Unsupported ANQP Info ID %u", info_id);
 		break;
 	}
 }
@@ -2775,6 +2863,7 @@
 	u16 info_id;
 	u16 slen;
 	struct wpa_bss *bss = NULL, *tmp;
+	const char *anqp_result = "SUCCESS";
 
 	wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
 		   " dialog_token=%u result=%d status_code=%u",
@@ -2782,17 +2871,19 @@
 	if (result != GAS_QUERY_SUCCESS) {
 		if (wpa_s->fetch_osu_icon_in_progress)
 			hs20_icon_fetch_failed(wpa_s);
-		return;
+		anqp_result = "FAILURE";
+		goto out;
 	}
 
 	pos = wpabuf_head(adv_proto);
 	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
 	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
-		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
-			   "Protocol in response");
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"ANQP: Unexpected Advertisement Protocol in response");
 		if (wpa_s->fetch_osu_icon_in_progress)
 			hs20_icon_fetch_failed(wpa_s);
-		return;
+		anqp_result = "INVALID_FRAME";
+		goto out;
 	}
 
 	/*
@@ -2817,8 +2908,9 @@
 		unsigned int left = end - pos;
 
 		if (left < 4) {
-			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
-			break;
+			wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Invalid element");
+			anqp_result = "INVALID_FRAME";
+			goto out_parse_done;
 		}
 		info_id = WPA_GET_LE16(pos);
 		pos += 2;
@@ -2826,24 +2918,30 @@
 		pos += 2;
 		left -= 4;
 		if (left < slen) {
-			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
-				   "for Info ID %u", info_id);
-			break;
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"ANQP: Invalid element length for Info ID %u",
+				info_id);
+			anqp_result = "INVALID_FRAME";
+			goto out_parse_done;
 		}
 		interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
 						slen);
 		pos += slen;
 	}
 
+out_parse_done:
 	hs20_notify_parse_done(wpa_s);
+out:
+	wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
+		MAC2STR(dst), anqp_result);
 }
 
 
 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
 					  struct wpa_scan_results *scan_res)
 {
-	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
-		   "ANQP fetch");
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"Interworking: Scan results available - start ANQP fetch");
 	interworking_start_fetch_anqp(wpa_s);
 }
 
@@ -2857,8 +2955,8 @@
 	wpa_s->auto_select = !!auto_select;
 	wpa_s->fetch_all_anqp = 0;
 	wpa_s->fetch_osu_info = 0;
-	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
-		   "selection");
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"Interworking: Start scan for network selection");
 	wpa_s->scan_res_handler = interworking_scan_res_handler;
 	wpa_s->normal_scans = 0;
 	wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -2919,8 +3017,8 @@
 	if (freq <= 0)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
-		   MAC2STR(dst), freq);
+	wpa_msg(wpa_s, 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);
 
@@ -2946,12 +3044,12 @@
 
 	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");
+		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
 		wpabuf_free(buf);
 		ret = -1;
 	} else
-		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
-			   "%u", res);
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"GAS: Query started with dialog token %u", res);
 
 	return ret;
 }
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 38ef745..3743dc0 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -24,7 +24,8 @@
 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
 			int *freqs);
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			 int only_add);
 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
 int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
 			      struct wpa_cred *cred,
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 13e9769..2282747 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -322,7 +322,7 @@
 			exitcode = -1;
 			break;
 		}
-		wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+		wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
 		if (wpa_s == NULL) {
 			exitcode = -1;
 			break;
diff --git a/wpa_supplicant/main_none.c b/wpa_supplicant/main_none.c
index 010c30a..4d3caf2 100644
--- a/wpa_supplicant/main_none.c
+++ b/wpa_supplicant/main_none.c
@@ -28,7 +28,7 @@
 	memset(&iface, 0, sizeof(iface));
 	/* TODO: set interface parameters */
 
-	if (wpa_supplicant_add_iface(global, &iface) == NULL)
+	if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL)
 		exitcode = -1;
 
 	if (exitcode == 0)
diff --git a/wpa_supplicant/main_winmain.c b/wpa_supplicant/main_winmain.c
index 93a68f1..e1dded0 100644
--- a/wpa_supplicant/main_winmain.c
+++ b/wpa_supplicant/main_winmain.c
@@ -61,7 +61,7 @@
 			exitcode = -1;
 			break;
 		}
-		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+		if (wpa_supplicant_add_iface(global, &ifaces[i], NULL) == NULL)
 			exitcode = -1;
 	}
 
diff --git a/wpa_supplicant/main_winsvc.c b/wpa_supplicant/main_winsvc.c
index 0b7d5ce..9950aa9 100644
--- a/wpa_supplicant/main_winsvc.c
+++ b/wpa_supplicant/main_winsvc.c
@@ -119,7 +119,7 @@
 
 	RegCloseKey(hk);
 
-	if (wpa_supplicant_add_iface(global, &iface) == NULL) {
+	if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL) {
 		if (skip_on_error)
 			wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
 				   "initialization failure", iface.ifname);
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7a4f3de..ca012e2 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -166,6 +166,7 @@
 	bss->conf = *conf->bss;
 	bss->conf->start_disabled = 1;
 	bss->conf->mesh = MESH_ENABLED;
+	bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
 	bss->iconf = conf;
 	ifmsh->conf = conf;
 
@@ -318,15 +319,13 @@
 	os_memset(&params, 0, sizeof(params));
 	params.meshid = ssid->ssid;
 	params.meshid_len = ssid->ssid_len;
-	params.freq = ssid->frequency;
+	ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
+	wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
 	if (ssid->beacon_int > 0)
 		params.beacon_int = ssid->beacon_int;
 	else if (wpa_s->conf->beacon_int > 0)
 		params.beacon_int = wpa_s->conf->beacon_int;
 	params.max_peer_links = wpa_s->conf->max_peer_links;
-#ifdef CONFIG_IEEE80211N
-	params.ht_mode = ssid->mesh_ht_mode;
-#endif /* CONFIG_IEEE80211N */
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
 		params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -341,9 +340,11 @@
 		params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
 		params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
 	}
+	params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
 
 	if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
+		wpa_drv_leave_mesh(wpa_s);
 		ret = -1;
 		goto out;
 	}
@@ -452,22 +453,23 @@
 		ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
 				  bss_basic_rate_set[0]);
 		if (os_snprintf_error(end - pos, ret))
-			return pos - buf;
+			goto fail;
 		pos += ret;
 
 		for (i = 1; i < bss_basic_rate_set_len; i++) {
 			ret = os_snprintf(pos, end - pos, " %d",
 					  bss_basic_rate_set[i]);
 			if (os_snprintf_error(end - pos, ret))
-				return pos - buf;
+				goto fail;
 			pos += ret;
 		}
 
 		ret = os_snprintf(pos, end - pos, "\n");
 		if (os_snprintf_error(end - pos, ret))
-			return pos - buf;
+			goto fail;
 		pos += ret;
 	}
+fail:
 	os_free(bss_basic_rate_set);
 
 	return pos - buf;
@@ -527,7 +529,7 @@
 	iface.driver_param = wpa_s->conf->driver_param;
 	iface.ctrl_interface = wpa_s->conf->ctrl_interface;
 
-	mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
 	if (!mesh_wpa_s) {
 		wpa_printf(MSG_ERROR,
 			   "mesh: Failed to create new wpa_supplicant interface");
@@ -535,6 +537,5 @@
 		return -1;
 	}
 	mesh_wpa_s->mesh_if_created = 1;
-	mesh_wpa_s->parent = wpa_s;
 	return 0;
 }
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index e7c53ea..b29b5ff 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -193,6 +193,11 @@
 
 	sta->my_lid = llid;
 	sta->peer_lid = 0;
+
+	/*
+	 * We do not use wpa_mesh_set_plink_state() here because there is no
+	 * entry in kernel yet.
+	 */
 	sta->plink_state = PLINK_LISTEN;
 }
 
@@ -229,8 +234,7 @@
 		  2 + 96 + /* AMPE */
 		  2 + 16;  /* MIC */
 #ifdef CONFIG_IEEE80211N
-	if (type != PLINK_CLOSE &&
-	    wpa_s->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+	if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
 		buf_len += 2 + 26 + /* HT capabilities */
 			   2 + 22;  /* HT operation */
 	}
@@ -323,8 +327,7 @@
 	}
 
 #ifdef CONFIG_IEEE80211N
-	if (type != PLINK_CLOSE &&
-	    wpa_s->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+	if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
 		pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
 		pos = hostapd_eid_ht_operation(bss, pos);
 		wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
@@ -350,9 +353,9 @@
 
 
 /* configure peering state in ours and driver's station entry */
-static void
-wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
-			 enum mesh_plink_state state)
+void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+			      struct sta_info *sta,
+			      enum mesh_plink_state state)
 {
 	struct hostapd_sta_add_params params;
 	int ret;
@@ -381,14 +384,7 @@
 
 	eloop_cancel_timeout(plink_timer, wpa_s, sta);
 
-	if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
-		ap_free_sta(hapd, sta);
-		return;
-	}
-
-	wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
-	sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
-	sta->mpm_retries = 0;
+	ap_free_sta(hapd, sta);
 }
 
 
@@ -419,7 +415,7 @@
 		/* confirm timer */
 		if (!reason)
 			reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
-		sta->plink_state = PLINK_HOLDING;
+		wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
 		eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000,
 			(conf->dot11MeshHoldingTimeout % 1000) * 1000,
 			plink_timer, wpa_s, sta);
@@ -523,33 +519,39 @@
 	mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
 }
 
-
-void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
-			    struct ieee802_11_elems *elems)
+/*
+ * Initialize a sta_info structure for a peer and upload it into the driver
+ * in preparation for beginning authentication or peering. This is done when a
+ * Beacon (secure or open mesh) or a peering open frame (for open mesh) is
+ * received from the peer for the first time.
+ */
+static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
+					   const u8 *addr,
+					   struct ieee802_11_elems *elems)
 {
 	struct hostapd_sta_add_params params;
 	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
 	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
 	struct sta_info *sta;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	int ret = 0;
+	int ret;
 
 	sta = ap_get_sta(data, addr);
 	if (!sta) {
 		sta = ap_sta_add(data, addr);
 		if (!sta)
-			return;
+			return NULL;
 	}
 
 	/* initialize sta */
-	if (copy_supp_rates(wpa_s, sta, elems))
-		return;
+	if (copy_supp_rates(wpa_s, sta, elems)) {
+		ap_free_sta(data, sta);
+		return NULL;
+	}
 
 	mesh_mpm_init_link(wpa_s, sta);
 
 #ifdef CONFIG_IEEE80211N
-	copy_sta_ht_capab(data, sta, elems->ht_capabilities,
-			elems->ht_capabilities_len);
+	copy_sta_ht_capab(data, sta, elems->ht_capabilities);
 	update_ht_state(data, sta);
 #endif /* CONFIG_IEEE80211N */
 
@@ -577,9 +579,26 @@
 		wpa_msg(wpa_s, MSG_ERROR,
 			"Driver failed to insert " MACSTR ": %d",
 			MAC2STR(addr), ret);
-		return;
+		ap_free_sta(data, sta);
+		return NULL;
 	}
 
+	return sta;
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			    struct ieee802_11_elems *elems)
+{
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+	struct sta_info *sta;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	sta = mesh_mpm_add_peer(wpa_s, addr, elems);
+	if (!sta)
+		return;
+
 	if (ssid && ssid->no_auto_peer) {
 		wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
 			MACSTR " because of no_auto_peer", MAC2STR(addr));
@@ -932,6 +951,15 @@
 	wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
 
 	sta = ap_get_sta(hapd, mgmt->sa);
+
+	/*
+	 * If this is an open frame from an unknown STA, and this is an
+	 * open mesh, then go ahead and add the peer before proceeding.
+	 */
+	if (!sta && action_field == PLINK_OPEN &&
+	    !(mconf->security & MESH_CONF_SEC_AMPE))
+		sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
+
 	if (!sta) {
 		wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
 		return;
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index 2f7f6a7..7ebaef0 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -15,6 +15,9 @@
 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
 void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
 void mesh_mpm_free_sta(struct sta_info *sta);
+void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+			      struct sta_info *sta,
+			      enum mesh_plink_state state);
 
 #ifdef CONFIG_MESH
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e6ae7c3..936002d 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -18,6 +18,7 @@
 #include "ap/hostapd.h"
 #include "ap/wpa_auth.h"
 #include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "wpas_glue.h"
@@ -26,6 +27,7 @@
 
 #define MESH_AUTH_TIMEOUT 10
 #define MESH_AUTH_RETRY 3
+#define MESH_AUTH_BLOCK_DURATION 3600
 
 void mesh_auth_timer(void *eloop_ctx, void *user_data)
 {
@@ -36,12 +38,28 @@
 		wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
 			   " (attempt %d) ",
 			   MAC2STR(sta->addr), sta->sae_auth_retry);
+		wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR,
+			MAC2STR(sta->addr));
 		if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
 			mesh_rsn_auth_sae_sta(wpa_s, sta);
 		} else {
+			if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
+				ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+				return;
+			}
+
 			/* block the STA if exceeded the number of attempts */
-			sta->plink_state = PLINK_BLOCKED;
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
 			sta->sae->state = SAE_NOTHING;
+			if (wpa_s->mesh_auth_block_duration <
+			    MESH_AUTH_BLOCK_DURATION)
+				wpa_s->mesh_auth_block_duration += 60;
+			eloop_register_timeout(wpa_s->mesh_auth_block_duration,
+					       0, mesh_auth_timer, wpa_s, sta);
+			wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
+				MACSTR " duration=%d",
+				MAC2STR(sta->addr),
+				wpa_s->mesh_auth_block_duration);
 		}
 		sta->sae_auth_retry++;
 	}
@@ -245,80 +263,23 @@
 }
 
 
-struct wpabuf *
-mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
-			  struct wpa_ssid *ssid, struct sta_info *sta)
+static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid,
+				     struct sta_info *sta)
 {
-	struct wpabuf *buf;
-	int len;
-
 	if (ssid->passphrase == NULL) {
 		wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
-		return NULL;
+		return -1;
 	}
 
 	if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
-		return NULL;
+		return -1;
 	}
 
-	if (sae_prepare_commit(wpa_s->own_addr, sta->addr,
-			       (u8 *) ssid->passphrase,
-			       os_strlen(ssid->passphrase), sta->sae) < 0) {
-		wpa_msg(wpa_s, MSG_DEBUG, "SAE: Could not pick PWE");
-		return NULL;
-	}
-
-	len = wpa_s->mesh_rsn->sae_token ?
-		wpabuf_len(wpa_s->mesh_rsn->sae_token) : 0;
-	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
-	if (buf == NULL)
-		return NULL;
-
-	sae_write_commit(sta->sae, buf, wpa_s->mesh_rsn->sae_token);
-
-	return buf;
-}
-
-
-static void mesh_rsn_send_auth(struct wpa_supplicant *wpa_s,
-			       const u8 *dst, const u8 *src,
-			       u16 auth_transaction, u16 resp,
-			       struct wpabuf *data)
-{
-	struct ieee80211_mgmt *auth;
-	u8 *buf;
-	size_t len, ielen = 0;
-
-	if (data)
-		ielen = wpabuf_len(data);
-	len = IEEE80211_HDRLEN + sizeof(auth->u.auth) + ielen;
-	buf = os_zalloc(len);
-	if (buf == NULL)
-		return;
-
-	auth = (struct ieee80211_mgmt *) buf;
-	auth->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_AUTH);
-	os_memcpy(auth->da, dst, ETH_ALEN);
-	os_memcpy(auth->sa, src, ETH_ALEN);
-	os_memcpy(auth->bssid, src, ETH_ALEN);
-
-	auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
-	auth->u.auth.auth_transaction = host_to_le16(auth_transaction);
-	auth->u.auth.status_code = host_to_le16(resp);
-
-	if (data)
-		os_memcpy(auth->u.auth.variable, wpabuf_head(data), ielen);
-
-	wpa_msg(wpa_s, MSG_DEBUG, "authentication frame: STA=" MACSTR
-		" auth_transaction=%d resp=%d (IE len=%lu)",
-		MAC2STR(dst), auth_transaction, resp, (unsigned long) ielen);
-	if (wpa_drv_send_mlme(wpa_s, buf, len, 0) < 0)
-		wpa_printf(MSG_INFO, "send_auth_reply: send_mlme failed: %s",
-			   strerror(errno));
-
-	os_free(buf);
+	return sae_prepare_commit(wpa_s->own_addr, sta->addr,
+				  (u8 *) ssid->passphrase,
+				  os_strlen(ssid->passphrase), sta->sae);
 }
 
 
@@ -326,9 +287,10 @@
 int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
 			  struct sta_info *sta)
 {
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	struct wpabuf *buf;
 	unsigned int rnd;
+	int ret;
 
 	if (!ssid) {
 		wpa_msg(wpa_s, MSG_DEBUG,
@@ -342,25 +304,22 @@
 			return -1;
 	}
 
-	buf = mesh_rsn_build_sae_commit(wpa_s, ssid, sta);
-	if (!buf)
+	if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
 		return -1;
 
 	wpa_msg(wpa_s, MSG_DEBUG,
 		"AUTH: started authentication with SAE peer: " MACSTR,
 		MAC2STR(sta->addr));
 
-	sta->sae->state = SAE_COMMITTED;
 	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+	ret = auth_sae_init_committed(hapd, sta);
+	if (ret)
+		return ret;
 
-	mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
-			   1, WLAN_STATUS_SUCCESS, buf);
-
+	eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
 	rnd = rand() % MESH_AUTH_TIMEOUT;
 	eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
 			       wpa_s, sta);
-	wpabuf_free(buf);
-
 	return 0;
 }
 
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index df1ce9e..ea7dbdb 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -690,13 +690,13 @@
 
 
 void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
-			       const char *subject, const char *cert_hash,
+			       const char *subject, const char *altsubject[],
+			       int num_altsubject, const char *cert_hash,
 			       const struct wpabuf *cert)
 {
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
 		"depth=%d subject='%s'%s%s",
-		depth, subject,
-		cert_hash ? " hash=" : "",
+		depth, subject, cert_hash ? " hash=" : "",
 		cert_hash ? cert_hash : "");
 
 	if (cert) {
@@ -714,11 +714,20 @@
 		}
 	}
 
+	if (altsubject) {
+		int i;
+
+		for (i = 0; i < num_altsubject; i++)
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+				"depth=%d %s", depth, altsubject[i]);
+	}
+
 	/* notify the old DBus API */
 	wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
 						 cert_hash, cert);
 	/* notify the new DBus API */
-	wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+	wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
+				       num_altsubject, cert_hash, cert);
 }
 
 
@@ -755,3 +764,22 @@
 	wpa_drv_roaming(wpa_s, !ssid->bssid_set,
 			ssid->bssid_set ? ssid->bssid : NULL);
 }
+
+
+void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+	if (ssid->disabled == 2) {
+		/* Changed from normal network profile to persistent group */
+		ssid->disabled = 0;
+		wpas_dbus_unregister_network(wpa_s, ssid->id);
+		ssid->disabled = 2;
+		wpas_dbus_register_persistent_group(wpa_s, ssid);
+	} else {
+		/* Changed from persistent group to normal network profile */
+		wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+		wpas_dbus_register_network(wpa_s, ssid);
+	}
+#endif /* CONFIG_P2P */
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 7feb530..b268332 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -121,7 +121,8 @@
 				struct wps_event_fail *fail);
 
 void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
-			       const char *subject, const char *cert_hash,
+			       const char *subject, const char *altsubject[],
+			       int num_altsubject, const char *cert_hash,
 			       const struct wpabuf *cert);
 void wpas_notify_preq(struct wpa_supplicant *wpa_s,
 		      const u8 *addr, const u8 *dst, const u8 *bssid,
@@ -130,5 +131,7 @@
 			    const char *parameter);
 void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
 					   struct wpa_ssid *ssid);
+void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 7a86347..63af83a 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -354,15 +354,18 @@
  */
 void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
 {
-	wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
-		   "notification");
+	wpa_printf(MSG_DEBUG,
+		   "Off-channel: Action frame sequence done notification: pending_action_tx=%p drv_offchan_tx=%d action_tx_wait_time=%d off_channel_freq=%d roc_waiting_drv_freq=%d",
+		   wpa_s->pending_action_tx,
+		   !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX),
+		   wpa_s->action_tx_wait_time, wpa_s->off_channel_freq,
+		   wpa_s->roc_waiting_drv_freq);
 	wpabuf_free(wpa_s->pending_action_tx);
 	wpa_s->pending_action_tx = NULL;
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
 	    wpa_s->action_tx_wait_time)
 		wpa_drv_send_action_cancel_wait(wpa_s);
-
-	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+	else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
 		wpa_drv_cancel_remain_on_channel(wpa_s);
 		wpa_s->off_channel_freq = 0;
 		wpa_s->roc_waiting_drv_freq = 0;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 42e5014..4c71ef4 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -22,6 +22,7 @@
 #include "ap/ap_drv_ops.h"
 #include "ap/wps_hostapd.h"
 #include "ap/p2p_hostapd.h"
+#include "ap/dfs.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
@@ -117,12 +118,14 @@
 static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 					     void *timeout_ctx);
 static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
-static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
-					int group_added);
+static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+				       int group_added);
 static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 static void wpas_stop_listen(void *ctx);
 static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+					enum wpa_driver_if_type type);
 
 
 /*
@@ -375,6 +378,13 @@
 		break;
 	case P2P_SCAN_FULL:
 		break;
+	case P2P_SCAN_SPECIFIC:
+		params->freqs = os_calloc(2, sizeof(int));
+		if (params->freqs == NULL)
+			goto fail;
+		params->freqs[0] = freq;
+		params->freqs[1] = 0;
+		break;
 	case P2P_SCAN_SOCIAL_PLUS_ONE:
 		params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
 					  sizeof(int));
@@ -475,6 +485,287 @@
 }
 
 
+/* Determine total number of clients in active groups where we are the GO */
+static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
+{
+	unsigned int count = 0;
+	struct wpa_ssid *s;
+
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		for (s = wpa_s->conf->ssid; s; s = s->next) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+				   wpa_s, s, s->disabled, s->p2p_group,
+				   s->mode);
+			if (!s->disabled && s->p2p_group &&
+			    s->mode == WPAS_MODE_P2P_GO) {
+				count += p2p_get_group_num_members(
+					wpa_s->p2p_group);
+			}
+		}
+	}
+
+	return count;
+}
+
+
+/* Find an interface for a P2P group where we are the GO */
+static struct wpa_supplicant *
+wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_supplicant *save = NULL;
+	struct wpa_ssid *s;
+
+	if (!wpa_s)
+		return NULL;
+
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		for (s = wpa_s->conf->ssid; s; s = s->next) {
+			if (s->disabled || !s->p2p_group ||
+			    s->mode != WPAS_MODE_P2P_GO)
+				continue;
+
+			/* Prefer a group with connected clients */
+			if (p2p_get_group_num_members(wpa_s->p2p_group))
+				return wpa_s;
+			save = wpa_s;
+		}
+	}
+
+	/* No group with connected clients, so pick the one without (if any) */
+	return save;
+}
+
+
+/* Find an active P2P group where we are the GO */
+static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
+						u8 *bssid)
+{
+	struct wpa_ssid *s, *empty = NULL;
+
+	if (!wpa_s)
+		return 0;
+
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		for (s = wpa_s->conf->ssid; s; s = s->next) {
+			if (s->disabled || !s->p2p_group ||
+			    s->mode != WPAS_MODE_P2P_GO)
+				continue;
+
+			os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
+			if (p2p_get_group_num_members(wpa_s->p2p_group))
+				return s;
+			empty = s;
+		}
+	}
+
+	return empty;
+}
+
+
+/* Find a persistent group where we are the GO */
+static struct wpa_ssid *
+wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *s;
+
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled == 2 && s->mode == WPAS_MODE_P2P_GO)
+			return s;
+	}
+
+	return NULL;
+}
+
+
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+{
+	struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+	struct wpa_ssid *s;
+	u8 conncap = P2PS_SETUP_NONE;
+	unsigned int owned_members = 0;
+	unsigned int owner = 0;
+	unsigned int client = 0;
+	struct wpa_supplicant *go_wpa_s;
+	struct wpa_ssid *persistent_go;
+	int p2p_no_group_iface;
+
+	wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+
+	/*
+	 * For non-concurrent capable devices:
+	 * If persistent_go, then no new.
+	 * If GO, then no client.
+	 * If client, then no GO.
+	 */
+	go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+	persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+	p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
+
+	wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
+		   go_wpa_s, persistent_go);
+
+	for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
+	     tmp_wpa_s = tmp_wpa_s->next) {
+		for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+				   tmp_wpa_s, s, s->disabled,
+				   s->p2p_group, s->mode);
+			if (!s->disabled && s->p2p_group) {
+				if (s->mode == WPAS_MODE_P2P_GO) {
+					owned_members +=
+						p2p_get_group_num_members(
+							tmp_wpa_s->p2p_group);
+					owner++;
+				} else
+					client++;
+			}
+		}
+	}
+
+	/* If not concurrent, restrict our choices */
+	if (p2p_no_group_iface) {
+		wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
+
+		if (client)
+			return P2PS_SETUP_NONE;
+
+		if (go_wpa_s) {
+			if (role == P2PS_SETUP_CLIENT ||
+			    incoming == P2PS_SETUP_GROUP_OWNER ||
+			    p2p_client_limit_reached(go_wpa_s->p2p_group))
+				return P2PS_SETUP_NONE;
+
+			return P2PS_SETUP_GROUP_OWNER;
+		}
+
+		if (persistent_go) {
+			if (role == P2PS_SETUP_NONE || role == P2PS_SETUP_NEW) {
+				if (!incoming)
+					return P2PS_SETUP_GROUP_OWNER |
+						P2PS_SETUP_CLIENT;
+				if (incoming == P2PS_SETUP_NEW) {
+					u8 r;
+
+					if (os_get_random(&r, sizeof(r)) < 0 ||
+					    (r & 1))
+						return P2PS_SETUP_CLIENT;
+					return P2PS_SETUP_GROUP_OWNER;
+				}
+			}
+		}
+	}
+
+	/* If a required role has been specified, handle it here */
+	if (role && role != P2PS_SETUP_NEW) {
+		switch (incoming) {
+		case P2PS_SETUP_NONE:
+		case P2PS_SETUP_NEW:
+		case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+		case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+			conncap = role;
+			goto grp_owner;
+
+		case P2PS_SETUP_GROUP_OWNER:
+			/*
+			 * Must be a complimentary role - cannot be a client to
+			 * more than one peer.
+			 */
+			if (incoming == role || client)
+				return P2PS_SETUP_NONE;
+
+			return P2PS_SETUP_CLIENT;
+
+		case P2PS_SETUP_CLIENT:
+			/* Must be a complimentary role */
+			if (incoming != role) {
+				conncap = P2PS_SETUP_GROUP_OWNER;
+				goto grp_owner;
+			}
+
+		default:
+			return P2PS_SETUP_NONE;
+		}
+	}
+
+	/*
+	 * For now, we only will support ownership of one group, and being a
+	 * client of one group. Therefore, if we have either an existing GO
+	 * group, or an existing client group, we will not do a new GO
+	 * negotiation, but rather try to re-use the existing groups.
+	 */
+	switch (incoming) {
+	case P2PS_SETUP_NONE:
+	case P2PS_SETUP_NEW:
+		if (client)
+			conncap = P2PS_SETUP_GROUP_OWNER;
+		else if (!owned_members)
+			conncap = P2PS_SETUP_NEW;
+		else if (incoming == P2PS_SETUP_NONE)
+			conncap = P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT;
+		else
+			conncap = P2PS_SETUP_CLIENT;
+		break;
+
+	case P2PS_SETUP_CLIENT:
+		conncap = P2PS_SETUP_GROUP_OWNER;
+		break;
+
+	case P2PS_SETUP_GROUP_OWNER:
+		if (!client)
+			conncap = P2PS_SETUP_CLIENT;
+		break;
+
+	case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+	case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+		if (client)
+			conncap = P2PS_SETUP_GROUP_OWNER;
+		else {
+			u8 r;
+
+			if (os_get_random(&r, sizeof(r)) < 0 ||
+			    (r & 1))
+				conncap = P2PS_SETUP_CLIENT;
+			else
+				conncap = P2PS_SETUP_GROUP_OWNER;
+		}
+		break;
+
+	default:
+		return P2PS_SETUP_NONE;
+	}
+
+grp_owner:
+	if ((conncap & P2PS_SETUP_GROUP_OWNER) ||
+	    (!incoming && (conncap & P2PS_SETUP_NEW))) {
+		if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
+			conncap &= ~P2PS_SETUP_GROUP_OWNER;
+		wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
+			   owner, owned_members, conncap);
+
+		s = wpas_p2p_get_persistent_go(wpa_s);
+
+		if (!s && !owner && p2p_no_group_iface) {
+			p2p_set_intended_addr(wpa_s->global->p2p,
+					      wpa_s->own_addr);
+		} else if (!s && !owner) {
+			if (wpas_p2p_add_group_interface(wpa_s,
+							 WPA_IF_P2P_GO) < 0) {
+				wpa_printf(MSG_ERROR,
+					   "P2P: Failed to allocate a new interface for the group");
+				return P2PS_SETUP_NONE;
+			}
+			wpa_s->global->pending_group_iface_for_p2ps = 1;
+			p2p_set_intended_addr(wpa_s->global->p2p,
+					      wpa_s->pending_interface_addr);
+		}
+	}
+
+	return conncap;
+}
+
+
 static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
 				 enum p2p_group_removal_reason removal_reason)
 {
@@ -837,7 +1128,7 @@
 		return;
 
 	for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
-		if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+		if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr,
 			      ETH_ALEN) != 0)
 			continue;
 
@@ -845,32 +1136,42 @@
 			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_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+			   s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+			   (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
 		os_memcpy(s->p2p_client_list +
-			  (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+			  (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr,
+			  ETH_ALEN);
+		os_memset(s->p2p_client_list +
+			  (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+			  0xff, ETH_ALEN);
 		found = 1;
 		break;
 	}
 
 	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);
+				     s->num_p2p_clients + 1, 2 * ETH_ALEN);
 		if (n == NULL)
 			return;
-		os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+		os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr,
+			  ETH_ALEN);
+		os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN,
+			  0xff, ETH_ALEN);
 		s->p2p_client_list = n;
 		s->num_p2p_clients++;
 	} else if (!found && s->p2p_client_list) {
 		/* 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);
+			   s->p2p_client_list + 2 * ETH_ALEN,
+			   (s->num_p2p_clients - 1) * 2 * ETH_ALEN);
 		os_memcpy(s->p2p_client_list +
-			  (s->num_p2p_clients - 1) * ETH_ALEN,
+			  (s->num_p2p_clients - 1) * 2 * ETH_ALEN,
 			  addr, ETH_ALEN);
+		os_memset(s->p2p_client_list +
+			  (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+			  0xff, ETH_ALEN);
 	}
 
 	if (wpa_s->parent->conf->update_config &&
@@ -1108,6 +1409,9 @@
 		wpa_s->pending_pd_before_join = 0;
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
 			"during p2p_connect-auto");
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_FALLBACK_TO_GO_NEG
+			       "reason=no-ACK-to-PD-Req");
 		wpas_p2p_fallback_to_go_neg(wpa_s, 0);
 		return;
 	}
@@ -1258,6 +1562,8 @@
 #endif /* CONFIG_WPS_NFC */
 	} else {
 		u16 dev_pw_id = DEV_PW_DEFAULT;
+		if (wpa_s->p2p_wps_method == WPS_P2PS)
+			dev_pw_id = DEV_PW_P2PS_DEFAULT;
 		if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
 			dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
 		wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
@@ -1338,6 +1644,16 @@
 }
 
 
+static void p2p_config_write(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->parent->conf->update_config &&
+	    wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+		wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
 static void p2p_go_configured(void *ctx, void *data)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -1361,6 +1677,16 @@
 				       params->persistent_group, "");
 		wpa_s->group_formation_reported = 1;
 
+		if (wpa_s->parent->p2ps_join_addr_valid) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2PS: Setting default PIN for " MACSTR,
+				MAC2STR(wpa_s->parent->p2ps_join_addr));
+			wpa_supplicant_ap_wps_pin(wpa_s,
+						  wpa_s->parent->p2ps_join_addr,
+						  "12345670", NULL, 0, 0);
+			wpa_s->parent->p2ps_join_addr_valid = 0;
+		}
+
 		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 		if (params->persistent_group) {
 			network_id = wpas_p2p_store_persistent_group(
@@ -1534,8 +1860,10 @@
 	d->ignore_old_scan_res = s->ignore_old_scan_res;
 	d->beacon_int = s->beacon_int;
 	d->dtim_period = s->dtim_period;
+	d->p2p_go_ctwindow = s->p2p_go_ctwindow;
 	d->disassoc_low_ack = s->disassoc_low_ack;
 	d->disable_scan_offload = s->disable_scan_offload;
+	d->passive_scan = s->passive_scan;
 
 	if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
 		d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
@@ -1628,6 +1956,7 @@
 			  wpa_s->pending_interface_name);
 	os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
 	wpa_s->pending_interface_name[0] = '\0';
+	wpa_s->global->pending_group_iface_for_p2ps = 0;
 }
 
 
@@ -1662,17 +1991,17 @@
 	else
 		iface.ctrl_interface = wpa_s->conf->ctrl_interface;
 	iface.driver_param = wpa_s->conf->driver_param;
-	group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
 	if (group_wpa_s == NULL) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to create new "
 			   "wpa_supplicant interface");
 		return NULL;
 	}
 	wpa_s->pending_interface_name[0] = '\0';
-	group_wpa_s->parent = wpa_s;
 	group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
 		P2P_GROUP_INTERFACE_CLIENT;
 	wpa_s->global->p2p_group_formation = group_wpa_s;
+	wpa_s->global->pending_group_iface_for_p2ps = 0;
 
 	wpas_p2p_clone_config(group_wpa_s, wpa_s);
 
@@ -1836,6 +2165,52 @@
 						    WFD_SUBELEM_DEVICE_INFO);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+	if (info->p2ps_instance) {
+		char str[256];
+		const u8 *buf = wpabuf_head(info->p2ps_instance);
+		size_t len = wpabuf_len(info->p2ps_instance);
+
+		while (len) {
+			u32 id;
+			u16 methods;
+			u8 str_len;
+
+			if (len < 4 + 2 + 1)
+				break;
+			id = WPA_GET_LE32(buf);
+			buf += sizeof(u32);
+			methods = WPA_GET_BE16(buf);
+			buf += sizeof(u16);
+			str_len = *buf++;
+			if (str_len > len - 4 - 2 - 1)
+				break;
+			os_memcpy(str, buf, str_len);
+			str[str_len] = '\0';
+			buf += str_len;
+			len -= str_len + sizeof(u32) + sizeof(u16) + sizeof(u8);
+
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_DEVICE_FOUND MACSTR
+				       " p2p_dev_addr=" MACSTR
+				       " pri_dev_type=%s name='%s'"
+				       " config_methods=0x%x"
+				       " dev_capab=0x%x"
+				       " group_capab=0x%x"
+				       " adv_id=%x asp_svc=%s%s",
+				       MAC2STR(addr),
+				       MAC2STR(info->p2p_device_addr),
+				       wps_dev_type_bin2str(
+					       info->pri_dev_type,
+					       devtype, sizeof(devtype)),
+				       info->device_name, methods,
+				       info->dev_capab, info->group_capab,
+				       id, str,
+				       info->vendor_elems ?
+				       " vendor_elems=1" : "");
+		}
+		goto done;
+	}
+
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
 		       " p2p_dev_addr=" MACSTR
 		       " pri_dev_type=%s name='%s' config_methods=0x%x "
@@ -1850,6 +2225,7 @@
 		       info->vendor_elems ? " vendor_elems=1" : "",
 		       new_device);
 
+done:
 	os_free(wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
@@ -2012,917 +2388,6 @@
 }
 
 
-/*
- * DNS Header section is used only to calculate compression pointers, so the
- * contents of this data does not matter, but the length needs to be reserved
- * in the virtual packet.
- */
-#define DNS_HEADER_LEN 12
-
-/*
- * 27-octet in-memory packet from P2P specification containing two implied
- * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
- */
-#define P2P_SD_IN_MEMORY_LEN 27
-
-static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
-				       u8 **spos, const u8 *end)
-{
-	while (*spos < end) {
-		u8 val = ((*spos)[0] & 0xc0) >> 6;
-		int len;
-
-		if (val == 1 || val == 2) {
-			/* These are reserved values in RFC 1035 */
-			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
-				   "sequence starting with 0x%x", val);
-			return -1;
-		}
-
-		if (val == 3) {
-			u16 offset;
-			u8 *spos_tmp;
-
-			/* Offset */
-			if (*spos + 2 > end) {
-				wpa_printf(MSG_DEBUG, "P2P: No room for full "
-					   "DNS offset field");
-				return -1;
-			}
-
-			offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
-			if (offset >= *spos - start) {
-				wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
-					   "pointer offset %u", offset);
-				return -1;
-			}
-
-			(*spos) += 2;
-			spos_tmp = start + offset;
-			return p2p_sd_dns_uncompress_label(upos, uend, start,
-							   &spos_tmp,
-							   *spos - 2);
-		}
-
-		/* Label */
-		len = (*spos)[0] & 0x3f;
-		if (len == 0)
-			return 0;
-
-		(*spos)++;
-		if (*spos + len > end) {
-			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
-				   "sequence - no room for label with length "
-				   "%u", len);
-			return -1;
-		}
-
-		if (*upos + len + 2 > uend)
-			return -2;
-
-		os_memcpy(*upos, *spos, len);
-		*spos += len;
-		*upos += len;
-		(*upos)[0] = '.';
-		(*upos)++;
-		(*upos)[0] = '\0';
-	}
-
-	return 0;
-}
-
-
-/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
- * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
- * not large enough */
-static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
-				 size_t msg_len, size_t offset)
-{
-	/* 27-octet in-memory packet from P2P specification */
-	const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
-		"\x04_udp\xC0\x11\x00\x0C\x00\x01";
-	u8 *tmp, *end, *spos;
-	char *upos, *uend;
-	int ret = 0;
-
-	if (buf_len < 2)
-		return -1;
-	if (offset > msg_len)
-		return -1;
-
-	tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
-	if (tmp == NULL)
-		return -1;
-	spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
-	end = spos + msg_len;
-	spos += offset;
-
-	os_memset(tmp, 0, DNS_HEADER_LEN);
-	os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
-	os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
-
-	upos = buf;
-	uend = buf + buf_len;
-
-	ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
-	if (ret) {
-		os_free(tmp);
-		return ret;
-	}
-
-	if (upos == buf) {
-		upos[0] = '.';
-		upos[1] = '\0';
-	} else if (upos[-1] == '.')
-		upos[-1] = '\0';
-
-	os_free(tmp);
-	return 0;
-}
-
-
-static struct p2p_srv_bonjour *
-wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
-			     const struct wpabuf *query)
-{
-	struct p2p_srv_bonjour *bsrv;
-	size_t len;
-
-	len = wpabuf_len(query);
-	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
-			 struct p2p_srv_bonjour, list) {
-		if (len == wpabuf_len(bsrv->query) &&
-		    os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
-			      len) == 0)
-			return bsrv;
-	}
-	return NULL;
-}
-
-
-static struct p2p_srv_upnp *
-wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
-			  const char *service)
-{
-	struct p2p_srv_upnp *usrv;
-
-	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
-			 struct p2p_srv_upnp, list) {
-		if (version == usrv->version &&
-		    os_strcmp(service, usrv->service) == 0)
-			return usrv;
-	}
-	return NULL;
-}
-
-
-static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
-					u8 srv_trans_id)
-{
-	u8 *len_pos;
-
-	if (wpabuf_tailroom(resp) < 5)
-		return;
-
-	/* Length (to be filled) */
-	len_pos = wpabuf_put(resp, 2);
-	wpabuf_put_u8(resp, srv_proto);
-	wpabuf_put_u8(resp, srv_trans_id);
-	/* Status Code */
-	wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
-	/* Response Data: empty */
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
-}
-
-
-static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
-				struct wpabuf *resp, u8 srv_trans_id)
-{
-	struct p2p_srv_bonjour *bsrv;
-	u8 *len_pos;
-
-	wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
-
-	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
-		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
-		return;
-	}
-
-	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
-			 struct p2p_srv_bonjour, list) {
-		if (wpabuf_tailroom(resp) <
-		    5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
-			return;
-		/* Length (to be filled) */
-		len_pos = wpabuf_put(resp, 2);
-		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-		wpabuf_put_u8(resp, srv_trans_id);
-		/* Status Code */
-		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
-				  wpabuf_head(bsrv->resp),
-				  wpabuf_len(bsrv->resp));
-		/* Response Data */
-		wpabuf_put_buf(resp, bsrv->query); /* Key */
-		wpabuf_put_buf(resp, bsrv->resp); /* Value */
-		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
-			     2);
-	}
-}
-
-
-static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
-			       size_t query_len)
-{
-	char str_rx[256], str_srv[256];
-
-	if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
-		return 0; /* Too short to include DNS Type and Version */
-	if (os_memcmp(query + query_len - 3,
-		      wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
-		      3) != 0)
-		return 0; /* Mismatch in DNS Type or Version */
-	if (query_len == wpabuf_len(bsrv->query) &&
-	    os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
-		return 1; /* Binary match */
-
-	if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
-				  0))
-		return 0; /* Failed to uncompress query */
-	if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
-				  wpabuf_head(bsrv->query),
-				  wpabuf_len(bsrv->query) - 3, 0))
-		return 0; /* Failed to uncompress service */
-
-	return os_strcmp(str_rx, str_srv) == 0;
-}
-
-
-static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
-				struct wpabuf *resp, u8 srv_trans_id,
-				const u8 *query, size_t query_len)
-{
-	struct p2p_srv_bonjour *bsrv;
-	u8 *len_pos;
-	int matches = 0;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
-			  query, query_len);
-	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
-		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
-		wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
-					    srv_trans_id);
-		return;
-	}
-
-	if (query_len == 0) {
-		wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
-		return;
-	}
-
-	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
-			 struct p2p_srv_bonjour, list) {
-		if (!match_bonjour_query(bsrv, query, query_len))
-			continue;
-
-		if (wpabuf_tailroom(resp) <
-		    5 + query_len + wpabuf_len(bsrv->resp))
-			return;
-
-		matches++;
-
-		/* Length (to be filled) */
-		len_pos = wpabuf_put(resp, 2);
-		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-		wpabuf_put_u8(resp, srv_trans_id);
-
-		/* Status Code */
-		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
-				  wpabuf_head(bsrv->resp),
-				  wpabuf_len(bsrv->resp));
-
-		/* Response Data */
-		wpabuf_put_data(resp, query, query_len); /* Key */
-		wpabuf_put_buf(resp, bsrv->resp); /* Value */
-
-		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
-	}
-
-	if (matches == 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
-			   "available");
-		if (wpabuf_tailroom(resp) < 5)
-			return;
-
-		/* Length (to be filled) */
-		len_pos = wpabuf_put(resp, 2);
-		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-		wpabuf_put_u8(resp, srv_trans_id);
-
-		/* Status Code */
-		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
-		/* Response Data: empty */
-		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
-			     2);
-	}
-}
-
-
-static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
-			     struct wpabuf *resp, u8 srv_trans_id)
-{
-	struct p2p_srv_upnp *usrv;
-	u8 *len_pos;
-
-	wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
-
-	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
-		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
-		return;
-	}
-
-	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
-			 struct p2p_srv_upnp, list) {
-		if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
-			return;
-
-		/* Length (to be filled) */
-		len_pos = wpabuf_put(resp, 2);
-		wpabuf_put_u8(resp, P2P_SERV_UPNP);
-		wpabuf_put_u8(resp, srv_trans_id);
-
-		/* Status Code */
-		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-		/* Response Data */
-		wpabuf_put_u8(resp, usrv->version);
-		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
-			   usrv->service);
-		wpabuf_put_str(resp, usrv->service);
-		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
-			     2);
-	}
-}
-
-
-static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
-			     struct wpabuf *resp, u8 srv_trans_id,
-			     const u8 *query, size_t query_len)
-{
-	struct p2p_srv_upnp *usrv;
-	u8 *len_pos;
-	u8 version;
-	char *str;
-	int count = 0;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
-			  query, query_len);
-
-	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
-		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
-		wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
-					    srv_trans_id);
-		return;
-	}
-
-	if (query_len == 0) {
-		wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
-		return;
-	}
-
-	if (wpabuf_tailroom(resp) < 5)
-		return;
-
-	/* Length (to be filled) */
-	len_pos = wpabuf_put(resp, 2);
-	wpabuf_put_u8(resp, P2P_SERV_UPNP);
-	wpabuf_put_u8(resp, srv_trans_id);
-
-	version = query[0];
-	str = os_malloc(query_len);
-	if (str == NULL)
-		return;
-	os_memcpy(str, query + 1, query_len - 1);
-	str[query_len - 1] = '\0';
-
-	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
-			 struct p2p_srv_upnp, list) {
-		if (version != usrv->version)
-			continue;
-
-		if (os_strcmp(str, "ssdp:all") != 0 &&
-		    os_strstr(usrv->service, str) == NULL)
-			continue;
-
-		if (wpabuf_tailroom(resp) < 2)
-			break;
-		if (count == 0) {
-			/* Status Code */
-			wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-			/* Response Data */
-			wpabuf_put_u8(resp, version);
-		} else
-			wpabuf_put_u8(resp, ',');
-
-		count++;
-
-		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
-			   usrv->service);
-		if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
-			break;
-		wpabuf_put_str(resp, usrv->service);
-	}
-	os_free(str);
-
-	if (count == 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
-			   "available");
-		/* Status Code */
-		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
-		/* Response Data: empty */
-	}
-
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
-}
-
-
-#ifdef CONFIG_WIFI_DISPLAY
-static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
-			    struct wpabuf *resp, u8 srv_trans_id,
-			    const u8 *query, size_t query_len)
-{
-	const u8 *pos;
-	u8 role;
-	u8 *len_pos;
-
-	wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
-
-	if (!wpa_s->global->wifi_display) {
-		wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
-		wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
-					    srv_trans_id);
-		return;
-	}
-
-	if (query_len < 1) {
-		wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
-			   "Role");
-		return;
-	}
-
-	if (wpabuf_tailroom(resp) < 5)
-		return;
-
-	pos = query;
-	role = *pos++;
-	wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
-
-	/* TODO: role specific handling */
-
-	/* Length (to be filled) */
-	len_pos = wpabuf_put(resp, 2);
-	wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
-	wpabuf_put_u8(resp, srv_trans_id);
-	wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
-
-	while (pos < query + query_len) {
-		if (*pos < MAX_WFD_SUBELEMS &&
-		    wpa_s->global->wfd_subelem[*pos] &&
-		    wpabuf_tailroom(resp) >=
-		    wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
-			wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
-				   "subelement %u", *pos);
-			wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
-		}
-		pos++;
-	}
-
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
-}
-#endif /* CONFIG_WIFI_DISPLAY */
-
-
-static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
-			    u16 update_indic, const u8 *tlvs, size_t tlvs_len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	const u8 *pos = tlvs;
-	const u8 *end = tlvs + tlvs_len;
-	const u8 *tlv_end;
-	u16 slen;
-	struct wpabuf *resp;
-	u8 srv_proto, srv_trans_id;
-	size_t buf_len;
-	char *buf;
-
-	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
-		    tlvs, tlvs_len);
-	buf_len = 2 * tlvs_len + 1;
-	buf = os_malloc(buf_len);
-	if (buf) {
-		wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
-		wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
-			     MACSTR " %u %u %s",
-			     freq, MAC2STR(sa), dialog_token, update_indic,
-			     buf);
-		os_free(buf);
-	}
-
-	if (wpa_s->p2p_sd_over_ctrl_iface) {
-		wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
-					   update_indic, tlvs, tlvs_len);
-		return; /* to be processed by an external program */
-	}
-
-	resp = wpabuf_alloc(10000);
-	if (resp == NULL)
-		return;
-
-	while (pos + 1 < end) {
-		wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
-		slen = WPA_GET_LE16(pos);
-		pos += 2;
-		if (pos + slen > end || slen < 2) {
-			wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
-				   "length");
-			wpabuf_free(resp);
-			return;
-		}
-		tlv_end = pos + slen;
-
-		srv_proto = *pos++;
-		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
-			   srv_proto);
-		srv_trans_id = *pos++;
-		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
-			   srv_trans_id);
-
-		wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
-			    pos, tlv_end - pos);
-
-
-		if (wpa_s->force_long_sd) {
-			wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
-				   "response");
-			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
-			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
-			goto done;
-		}
-
-		switch (srv_proto) {
-		case P2P_SERV_ALL_SERVICES:
-			wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
-				   "for all services");
-			if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
-			    dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
-				wpa_printf(MSG_DEBUG, "P2P: No service "
-					   "discovery protocols available");
-				wpas_sd_add_proto_not_avail(
-					resp, P2P_SERV_ALL_SERVICES,
-					srv_trans_id);
-				break;
-			}
-			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
-			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
-			break;
-		case P2P_SERV_BONJOUR:
-			wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
-					    pos, tlv_end - pos);
-			break;
-		case P2P_SERV_UPNP:
-			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);
-			wpas_sd_add_proto_not_avail(resp, srv_proto,
-						    srv_trans_id);
-			break;
-		}
-
-		pos = tlv_end;
-	}
-
-done:
-	wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
-				   update_indic, tlvs, tlvs_len);
-
-	wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
-
-	wpabuf_free(resp);
-}
-
-
-static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
-			     const u8 *tlvs, size_t tlvs_len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	const u8 *pos = tlvs;
-	const u8 *end = tlvs + tlvs_len;
-	const u8 *tlv_end;
-	u16 slen;
-	size_t buf_len;
-	char *buf;
-
-	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
-		    tlvs, tlvs_len);
-	if (tlvs_len > 1500) {
-		/* TODO: better way for handling this */
-		wpa_msg_ctrl(wpa_s, MSG_INFO,
-			     P2P_EVENT_SERV_DISC_RESP MACSTR
-			     " %u <long response: %u bytes>",
-			     MAC2STR(sa), update_indic,
-			     (unsigned int) tlvs_len);
-	} else {
-		buf_len = 2 * tlvs_len + 1;
-		buf = os_malloc(buf_len);
-		if (buf) {
-			wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
-			wpa_msg_ctrl(wpa_s, MSG_INFO,
-				     P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
-				     MAC2STR(sa), update_indic, buf);
-			os_free(buf);
-		}
-	}
-
-	while (pos < end) {
-		u8 srv_proto, srv_trans_id, status;
-
-		wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
-		slen = WPA_GET_LE16(pos);
-		pos += 2;
-		if (pos + slen > end || slen < 3) {
-			wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
-				   "length");
-			return;
-		}
-		tlv_end = pos + slen;
-
-		srv_proto = *pos++;
-		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
-			   srv_proto);
-		srv_trans_id = *pos++;
-		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
-			   srv_trans_id);
-		status = *pos++;
-		wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
-			   status);
-
-		wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
-			    pos, tlv_end - pos);
-
-		pos = tlv_end;
-	}
-
-	wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
-}
-
-
-u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
-			const struct wpabuf *tlvs)
-{
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return 0;
-	return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
-}
-
-
-u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
-			     u8 version, const char *query)
-{
-	struct wpabuf *tlvs;
-	u64 ret;
-
-	tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
-	if (tlvs == NULL)
-		return 0;
-	wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
-	wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
-	wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
-	wpabuf_put_u8(tlvs, version);
-	wpabuf_put_str(tlvs, query);
-	ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
-	wpabuf_free(tlvs);
-	return ret;
-}
-
-
-#ifdef CONFIG_WIFI_DISPLAY
-
-static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
-				   const struct wpabuf *tlvs)
-{
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return 0;
-	return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
-}
-
-
-#define MAX_WFD_SD_SUBELEMS 20
-
-static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
-				const char *subelems)
-{
-	u8 *len;
-	const char *pos;
-	int val;
-	int count = 0;
-
-	len = wpabuf_put(tlvs, 2);
-	wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
-	wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
-
-	wpabuf_put_u8(tlvs, role);
-
-	pos = subelems;
-	while (*pos) {
-		val = atoi(pos);
-		if (val >= 0 && val < 256) {
-			wpabuf_put_u8(tlvs, val);
-			count++;
-			if (count == MAX_WFD_SD_SUBELEMS)
-				break;
-		}
-		pos = os_strchr(pos + 1, ',');
-		if (pos == NULL)
-			break;
-		pos++;
-	}
-
-	WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
-}
-
-
-u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
-				     const u8 *dst, const char *role)
-{
-	struct wpabuf *tlvs;
-	u64 ret;
-	const char *subelems;
-	u8 id = 1;
-
-	subelems = os_strchr(role, ' ');
-	if (subelems == NULL)
-		return 0;
-	subelems++;
-
-	tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
-	if (tlvs == NULL)
-		return 0;
-
-	if (os_strstr(role, "[source]"))
-		wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
-	if (os_strstr(role, "[pri-sink]"))
-		wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
-	if (os_strstr(role, "[sec-sink]"))
-		wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
-	if (os_strstr(role, "[source+sink]"))
-		wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
-
-	ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
-	wpabuf_free(tlvs);
-	return ret;
-}
-
-#endif /* CONFIG_WIFI_DISPLAY */
-
-
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
-{
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return -1;
-	return p2p_sd_cancel_request(wpa_s->global->p2p,
-				     (void *) (uintptr_t) req);
-}
-
-
-void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
-			  const u8 *dst, u8 dialog_token,
-			  const struct wpabuf *resp_tlvs)
-{
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return;
-	p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
-			resp_tlvs);
-}
-
-
-void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->global->p2p)
-		p2p_sd_service_update(wpa_s->global->p2p);
-}
-
-
-static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
-{
-	dl_list_del(&bsrv->list);
-	wpabuf_free(bsrv->query);
-	wpabuf_free(bsrv->resp);
-	os_free(bsrv);
-}
-
-
-static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
-{
-	dl_list_del(&usrv->list);
-	os_free(usrv->service);
-	os_free(usrv);
-}
-
-
-void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
-{
-	struct p2p_srv_bonjour *bsrv, *bn;
-	struct p2p_srv_upnp *usrv, *un;
-
-	dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
-			      struct p2p_srv_bonjour, list)
-		wpas_p2p_srv_bonjour_free(bsrv);
-
-	dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
-			      struct p2p_srv_upnp, list)
-		wpas_p2p_srv_upnp_free(usrv);
-
-	wpas_p2p_sd_service_update(wpa_s);
-}
-
-
-int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
-				 struct wpabuf *query, struct wpabuf *resp)
-{
-	struct p2p_srv_bonjour *bsrv;
-
-	bsrv = os_zalloc(sizeof(*bsrv));
-	if (bsrv == NULL)
-		return -1;
-	bsrv->query = query;
-	bsrv->resp = resp;
-	dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
-
-	wpas_p2p_sd_service_update(wpa_s);
-	return 0;
-}
-
-
-int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
-				 const struct wpabuf *query)
-{
-	struct p2p_srv_bonjour *bsrv;
-
-	bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
-	if (bsrv == NULL)
-		return -1;
-	wpas_p2p_srv_bonjour_free(bsrv);
-	wpas_p2p_sd_service_update(wpa_s);
-	return 0;
-}
-
-
-int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
-			      const char *service)
-{
-	struct p2p_srv_upnp *usrv;
-
-	if (wpas_p2p_service_get_upnp(wpa_s, version, service))
-		return 0; /* Already listed */
-	usrv = os_zalloc(sizeof(*usrv));
-	if (usrv == NULL)
-		return -1;
-	usrv->version = version;
-	usrv->service = os_strdup(service);
-	if (usrv->service == NULL) {
-		os_free(usrv);
-		return -1;
-	}
-	dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
-
-	wpas_p2p_sd_service_update(wpa_s);
-	return 0;
-}
-
-
-int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
-			      const char *service)
-{
-	struct p2p_srv_upnp *usrv;
-
-	usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
-	if (usrv == NULL)
-		return -1;
-	wpas_p2p_srv_upnp_free(usrv);
-	wpas_p2p_sd_service_update(wpa_s);
-	return 0;
-}
-
-
 static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
 					 const u8 *peer, const char *params,
 					 unsigned int generated_pin)
@@ -3044,13 +2509,18 @@
 
 
 static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
-				enum p2p_prov_disc_status status)
+				enum p2p_prov_disc_status status,
+				u32 adv_id, const u8 *adv_mac,
+				const char *deferred_session_resp)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
 	if (wpa_s->p2p_fallback_to_go_neg) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
 			"failed - fall back to GO Negotiation");
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_FALLBACK_TO_GO_NEG
+			       "reason=PD-failed");
 		wpas_p2p_fallback_to_go_neg(wpa_s, 0);
 		return;
 	}
@@ -3064,9 +2534,21 @@
 		return;
 	}
 
-	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
-		       " p2p_dev_addr=" MACSTR " status=%d",
-		       MAC2STR(peer), status);
+	if (adv_id && adv_mac && deferred_session_resp) {
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+			       " p2p_dev_addr=" MACSTR " status=%d adv_id=%x"
+			       " deferred_session_resp='%s'",
+			       MAC2STR(peer), status, adv_id,
+			       deferred_session_resp);
+	} else if (adv_id && adv_mac) {
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+			       " p2p_dev_addr=" MACSTR " status=%d adv_id=%x",
+			       MAC2STR(peer), status, adv_id);
+	} else {
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+			       " p2p_dev_addr=" MACSTR " status=%d",
+			       MAC2STR(peer), status);
+	}
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
 					    status, 0, 0);
@@ -3148,14 +2630,14 @@
 		}
 
 #ifdef CONFIG_WPS_NFC
-		if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
-		    dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+		if (dev_pw_id >= 0 && wpa_s->p2p_nfc_tag_enabled &&
+		    dev_pw_id == wpa_s->p2p_oob_dev_pw_id) {
 			wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
-			wpa_s->parent->p2p_wps_method = WPS_NFC;
-			wpa_s->parent->pending_join_wps_method = WPS_NFC;
-			os_memcpy(wpa_s->parent->pending_join_dev_addr,
+			wpa_s->p2p_wps_method = WPS_NFC;
+			wpa_s->pending_join_wps_method = WPS_NFC;
+			os_memcpy(wpa_s->pending_join_dev_addr,
 				  go_dev_addr, ETH_ALEN);
-			os_memcpy(wpa_s->parent->pending_join_iface_addr,
+			os_memcpy(wpa_s->pending_join_iface_addr,
 				  bssid, ETH_ALEN);
 			goto accept_inv;
 		}
@@ -3348,7 +2830,7 @@
 		return;
 
 	for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
-		if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+		if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer,
 			      ETH_ALEN) == 0)
 			break;
 	}
@@ -3368,9 +2850,9 @@
 		   "group %d client list%s",
 		   MAC2STR(peer), ssid->id,
 		   inv ? " due to invitation result" : "");
-	os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
-		   ssid->p2p_client_list + (i + 1) * ETH_ALEN,
-		   (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+	os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN,
+		   ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+		   (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
 	ssid->num_p2p_clients--;
 	if (wpa_s->parent->conf->update_config &&
 	    wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
@@ -3966,12 +3448,11 @@
 	}
 	iface.conf_p2p_dev = NULL;
 
-	p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
 	if (!p2pdev_wpa_s) {
 		wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
 		return -1;
 	}
-	p2pdev_wpa_s->parent = wpa_s;
 	wpa_s->p2p_dev = p2pdev_wpa_s;
 
 	wpa_s->pending_interface_name[0] = '\0';
@@ -4001,6 +3482,337 @@
 }
 
 
+static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
+				     size_t ssid_len, u8 *go_dev_addr,
+				     u8 *ret_ssid, size_t *ret_ssid_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *s;
+
+	s = wpas_p2p_get_persistent(wpa_s, addr, ssid, ssid_len);
+	if (s) {
+		os_memcpy(ret_ssid, s->ssid, s->ssid_len);
+		*ret_ssid_len = s->ssid_len;
+		os_memcpy(go_dev_addr, s->bssid, ETH_ALEN);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpas_get_go_info(void *ctx, u8 *intended_addr,
+			    u8 *ssid, size_t *ssid_len, int *group_iface)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *s;
+	u8 bssid[ETH_ALEN];
+
+	s = wpas_p2p_group_go_ssid(wpa_s, bssid);
+	if (!s) {
+		s = wpas_p2p_get_persistent_go(wpa_s);
+		if (s)
+			os_memcpy(bssid, s->bssid, ETH_ALEN);
+	}
+
+	*group_iface = wpas_p2p_create_iface(wpa_s);
+	if (!s)
+		return 0;
+
+	os_memcpy(intended_addr, bssid, ETH_ALEN);
+	os_memcpy(ssid, s->ssid, s->ssid_len);
+	*ssid_len = s->ssid_len;
+
+	return 1;
+}
+
+
+static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go,
+				    const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *s;
+	int save_config = 0;
+	size_t i;
+
+	/* Start with our first choice of Persistent Groups */
+	while ((s = wpas_p2p_get_persistent(wpa_s, peer, NULL, 0))) {
+		if (go && ssid && ssid_len &&
+		    s->ssid_len == ssid_len &&
+		    os_memcmp(go, s->bssid, ETH_ALEN) == 0 &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			break;
+
+		/* Remove stale persistent group */
+		if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+			wpa_config_remove_network(wpa_s->conf, s->id);
+			save_config = 1;
+			continue;
+		}
+
+		for (i = 0; i < s->num_p2p_clients; i++) {
+			if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
+				      peer, ETH_ALEN) != 0)
+				continue;
+
+			os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+				   s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+				   (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
+			break;
+		}
+		s->num_p2p_clients--;
+		save_config = 1;
+	}
+
+	if (save_config)
+		p2p_config_write(wpa_s);
+
+	/* Return TRUE if valid SSID remains */
+	return s != NULL;
+}
+
+
+static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
+				    const u8 *adv_mac, const u8 *ses_mac,
+				    const u8 *grp_mac, u32 adv_id, u32 ses_id,
+				    u8 conncap, int passwd_id,
+				    const u8 *persist_ssid,
+				    size_t persist_ssid_size, int response_done,
+				    int prov_start, const char *session_info)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	u8 mac[ETH_ALEN];
+	struct wpa_ssid *persistent_go, *stale, *s;
+	int save_config = 0;
+	struct wpa_supplicant *go_wpa_s;
+
+	if (!dev)
+		return;
+
+	os_memset(mac, 0, ETH_ALEN);
+	if (!adv_mac)
+		adv_mac = mac;
+	if (!ses_mac)
+		ses_mac = mac;
+	if (!grp_mac)
+		grp_mac = mac;
+
+	if (prov_start) {
+		if (session_info == NULL) {
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_P2PS_PROVISION_START MACSTR
+				       " adv_id=%x conncap=%x"
+				       " adv_mac=" MACSTR
+				       " session=%x mac=" MACSTR
+				       " dev_passwd_id=%d",
+				       MAC2STR(dev), adv_id, conncap,
+				       MAC2STR(adv_mac),
+				       ses_id, MAC2STR(ses_mac),
+				       passwd_id);
+		} else {
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_P2PS_PROVISION_START MACSTR
+				       " adv_id=%x conncap=%x"
+				       " adv_mac=" MACSTR
+				       " session=%x mac=" MACSTR
+				       " dev_passwd_id=%d info='%s'",
+				       MAC2STR(dev), adv_id, conncap,
+				       MAC2STR(adv_mac),
+				       ses_id, MAC2STR(ses_mac),
+				       passwd_id, session_info);
+		}
+		return;
+	}
+
+	go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+	persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+	if (status && status != P2P_SC_SUCCESS_DEFERRED) {
+		if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+			wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+		if (persistent_go && !persistent_go->num_p2p_clients) {
+			/* remove empty persistent GO */
+			wpa_config_remove_network(wpa_s->conf,
+						  persistent_go->id);
+		}
+
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+			       " status=%d"
+			       " adv_id=%x adv_mac=" MACSTR
+			       " session=%x mac=" MACSTR,
+			       MAC2STR(dev), status,
+			       adv_id, MAC2STR(adv_mac),
+			       ses_id, MAC2STR(ses_mac));
+		return;
+	}
+
+	/* Clean up stale persistent groups with this device */
+	s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+				    persist_ssid_size);
+	for (;;) {
+		stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0);
+		if (!stale)
+			break;
+
+		if (s && s->ssid_len == stale->ssid_len &&
+		    os_memcmp(stale->bssid, s->bssid, ETH_ALEN) == 0 &&
+		    os_memcmp(stale->ssid, s->ssid, s->ssid_len) == 0)
+			break;
+
+		/* Remove stale persistent group */
+		if (stale->mode != WPAS_MODE_P2P_GO ||
+		    stale->num_p2p_clients <= 1) {
+			wpa_config_remove_network(wpa_s->conf, stale->id);
+		} else {
+			size_t i;
+
+			for (i = 0; i < stale->num_p2p_clients; i++) {
+				if (os_memcmp(stale->p2p_client_list +
+					      i * ETH_ALEN,
+					      dev, ETH_ALEN) == 0) {
+					os_memmove(stale->p2p_client_list +
+						   i * ETH_ALEN,
+						   stale->p2p_client_list +
+						   (i + 1) * ETH_ALEN,
+						   (stale->num_p2p_clients -
+						    i - 1) * ETH_ALEN);
+					break;
+				}
+			}
+			stale->num_p2p_clients--;
+		}
+		save_config = 1;
+	}
+
+	if (save_config)
+		p2p_config_write(wpa_s);
+
+	if (s) {
+		if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+			wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+		if (persistent_go && s != persistent_go &&
+		    !persistent_go->num_p2p_clients) {
+			/* remove empty persistent GO */
+			wpa_config_remove_network(wpa_s->conf,
+						  persistent_go->id);
+			/* Save config */
+		}
+
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+			       " status=%d"
+			       " adv_id=%x adv_mac=" MACSTR
+			       " session=%x mac=" MACSTR
+			       " persist=%d",
+			       MAC2STR(dev), status,
+			       adv_id, MAC2STR(adv_mac),
+			       ses_id, MAC2STR(ses_mac), s->id);
+		return;
+	}
+
+	if (conncap == P2PS_SETUP_GROUP_OWNER) {
+		const char *go_ifname = NULL;
+		if (!go_wpa_s) {
+			wpa_s->global->pending_p2ps_group = 1;
+
+			if (wpa_s->conf->p2p_no_group_iface)
+				go_ifname = wpa_s->ifname;
+			else if (wpa_s->pending_interface_name[0])
+				go_ifname = wpa_s->pending_interface_name;
+
+			if (!go_ifname) {
+				wpas_p2ps_prov_complete(
+					wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
+					dev, adv_mac, ses_mac,
+					NULL, adv_id, ses_id, 0, 0,
+					NULL, 0, 0, 0, NULL);
+				return;
+			}
+
+			/* If PD Resp complete, start up the GO */
+			if (response_done && persistent_go) {
+				wpas_p2p_group_add_persistent(
+					wpa_s, persistent_go,
+					0, 0, 0, 0, 0, NULL,
+					persistent_go->mode ==
+					WPAS_MODE_P2P_GO ?
+					P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+					0);
+			} else if (response_done) {
+				wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+			}
+
+			if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+				os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+				wpa_s->p2ps_join_addr_valid = 1;
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"P2PS: Saving PIN for " MACSTR,
+					MAC2STR(dev));
+			}
+		} else if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+			go_ifname = go_wpa_s->ifname;
+
+			wpa_dbg(go_wpa_s, MSG_DEBUG,
+				"P2P: Setting PIN-1 For " MACSTR, MAC2STR(dev));
+			wpa_supplicant_ap_wps_pin(go_wpa_s, dev, "12345670",
+						  NULL, 0, 0);
+
+			os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+			wpa_s->p2ps_join_addr_valid = 1;
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2PS: Saving PIN for " MACSTR, MAC2STR(dev));
+		}
+
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+			       " status=%d conncap=%x"
+			       " adv_id=%x adv_mac=" MACSTR
+			       " session=%x mac=" MACSTR
+			       " dev_passwd_id=%d go=%s",
+			       MAC2STR(dev), status, conncap,
+			       adv_id, MAC2STR(adv_mac),
+			       ses_id, MAC2STR(ses_mac),
+			       passwd_id, go_ifname);
+		return;
+	}
+
+	if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+		wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+	if (persistent_go && !persistent_go->num_p2p_clients) {
+		/* remove empty persistent GO */
+		wpa_config_remove_network(wpa_s->conf, persistent_go->id);
+	}
+
+	if (conncap == P2PS_SETUP_CLIENT) {
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+			       " status=%d conncap=%x"
+			       " adv_id=%x adv_mac=" MACSTR
+			       " session=%x mac=" MACSTR
+			       " dev_passwd_id=%d join=" MACSTR,
+			       MAC2STR(dev), status, conncap,
+			       adv_id, MAC2STR(adv_mac),
+			       ses_id, MAC2STR(ses_mac),
+			       passwd_id, MAC2STR(grp_mac));
+	} else {
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+			       " status=%d conncap=%x"
+			       " adv_id=%x adv_mac=" MACSTR
+			       " session=%x mac=" MACSTR
+			       " dev_passwd_id=%d",
+			       MAC2STR(dev), status, conncap,
+			       adv_id, MAC2STR(adv_mac),
+			       ses_id, MAC2STR(ses_mac),
+			       passwd_id);
+	}
+}
+
+
 static int _wpas_p2p_in_progress(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -4008,6 +3820,33 @@
 }
 
 
+static int wpas_prov_disc_resp_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *persistent_go;
+
+	if (!wpa_s->global->pending_p2ps_group)
+		return 0;
+
+	wpa_s->global->pending_p2ps_group = 0;
+
+	if (wpas_p2p_get_go_group(wpa_s))
+		return 0;
+	persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+	if (persistent_go) {
+		wpas_p2p_group_add_persistent(
+			wpa_s, persistent_go, 0, 0, 0, 0, 0, NULL,
+			persistent_go->mode == WPAS_MODE_P2P_GO ?
+			P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
+	} else {
+		wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+	}
+
+	return 1;
+}
+
+
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -4055,6 +3894,12 @@
 	p2p.presence_resp = wpas_presence_resp;
 	p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
 	p2p.is_p2p_in_progress = _wpas_p2p_in_progress;
+	p2p.get_persistent_group = wpas_get_persistent_group;
+	p2p.get_go_info = wpas_get_go_info;
+	p2p.remove_stale_groups = wpas_remove_stale_groups;
+	p2p.p2ps_prov_complete = wpas_p2ps_prov_complete;
+	p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
+	p2p.p2ps_group_capability = p2ps_group_capability;
 
 	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
 	os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -4474,7 +4319,7 @@
 		wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
 			   MAC2STR(wpa_s->pending_join_dev_addr), join);
 		if (p2p_prov_disc_req(wpa_s->global->p2p,
-				      wpa_s->pending_join_dev_addr,
+				      wpa_s->pending_join_dev_addr, NULL,
 				      wpa_s->pending_pd_config_methods, join,
 				      0, wpa_s->user_initiated_pd) < 0) {
 			wpa_s->p2p_auto_pd = 0;
@@ -4492,6 +4337,9 @@
 		if (join < 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
 				   "running a GO -> use GO Negotiation");
+			wpa_msg_global(wpa_s->parent, MSG_INFO,
+				       P2P_EVENT_FALLBACK_TO_GO_NEG
+				       "reason=peer-not-running-GO");
 			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,
@@ -4507,8 +4355,11 @@
 		wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
 			   "try to join the group", join ? "" :
 			   " in older scan");
-		if (!join)
+		if (!join) {
+			wpa_msg_global(wpa_s->parent, MSG_INFO,
+				       P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED);
 			wpa_s->p2p_fallback_to_go_neg = 1;
+		}
 	}
 
 	freq = p2p_get_oper_freq(wpa_s->global->p2p,
@@ -4603,7 +4454,8 @@
 		}
 
 		if (p2p_prov_disc_req(wpa_s->global->p2p,
-				      wpa_s->pending_join_dev_addr, method, 1,
+				      wpa_s->pending_join_dev_addr,
+				      NULL, method, 1,
 				      freq, wpa_s->user_initiated_pd) < 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
 				   "Discovery Request before joining an "
@@ -4855,11 +4707,22 @@
 		else
 			ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
 		if (!ret) {
-			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
-				   "(%u MHz) is not supported for P2P uses",
-				   freq);
-			res = -3;
-			goto exit_free;
+			if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+			    ieee80211_is_dfs(freq)) {
+				/*
+				 * If freq is a DFS channel and DFS is offloaded
+				 * to the driver, allow P2P GO to use it.
+				 */
+				wpa_printf(MSG_DEBUG,
+					   "P2P: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to the driver",
+					   freq);
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "P2P: The forced channel (%u MHz) is not supported for P2P uses",
+					   freq);
+				res = -3;
+				goto exit_free;
+			}
 		}
 
 		for (i = 0; i < num; i++) {
@@ -4960,6 +4823,7 @@
 	wpa_s->global->add_psk = NULL;
 
 	wpa_s->global->p2p_fail_on_wps_complete = 0;
+	wpa_s->global->pending_p2ps_group = 0;
 
 	if (go_intent < 0)
 		go_intent = wpa_s->conf->p2p_go_intent;
@@ -5078,7 +4942,11 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+	wpa_printf(MSG_DEBUG, "P2P: remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u duration=%u)",
+		   wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+		   wpa_s->roc_waiting_drv_freq, freq, duration);
+	if (wpa_s->off_channel_freq &&
+	    wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
 		p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
 			      wpa_s->pending_listen_duration);
 		wpa_s->pending_listen_freq = 0;
@@ -5225,6 +5093,17 @@
 	}
 
 	if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+		if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+		    ieee80211_is_dfs(freq)) {
+			/*
+			 * If freq is a DFS channel and DFS is offloaded to the
+			 * driver, allow P2P GO to use it.
+			 */
+			wpa_printf(MSG_DEBUG, "P2P: "
+				   "%s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded",
+				   __func__, freq);
+			return freq;
+		}
 		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
 			   "(%u MHz) is not supported for P2P uses",
 			   freq);
@@ -5262,6 +5141,24 @@
 			goto out;
 	}
 
+	/* try all channels in operating class 115 */
+	for (i = 0; i < 4; i++) {
+		params->freq = 5180 + i * 20;
+		if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+		    freq_included(channels, params->freq) &&
+		    p2p_supported_freq(wpa_s->global->p2p, params->freq))
+			goto out;
+	}
+
+	/* try all channels in operating class 124 */
+	for (i = 0; i < 4; i++) {
+		params->freq = 5745 + i * 20;
+		if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+		    freq_included(channels, params->freq) &&
+		    p2p_supported_freq(wpa_s->global->p2p, params->freq))
+			goto out;
+	}
+
 	/* try social channel class 180 channel 2 */
 	params->freq = 58320 + 1 * 2160;
 	if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
@@ -5278,7 +5175,7 @@
 			goto out;
 	}
 
-	wpa_printf(MSG_DEBUG, "P2P: No 2.4 and 60 GHz channel allowed");
+	wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed");
 	return -1;
 out:
 	wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
@@ -5488,10 +5385,21 @@
 		return -1;
 	if (params.freq &&
 	    !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
-		wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
-			   "(%u MHz) is not supported for P2P uses",
-			   params.freq);
-		return -1;
+		if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+		    ieee80211_is_dfs(params.freq)) {
+			/*
+			 * If freq is a DFS channel and DFS is offloaded to the
+			 * driver, allow P2P GO to use it.
+			 */
+			wpa_printf(MSG_DEBUG,
+				   "P2P: %s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to driver",
+				__func__, params.freq);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: The selected channel for GO (%u MHz) is not supported for P2P uses",
+				   params.freq);
+			return -1;
+		}
 	}
 	p2p_go_params(wpa_s->global->p2p, &params);
 	params.persistent_group = persistent_group;
@@ -5596,18 +5504,26 @@
 			    (freq > 0 && !freq_included(channels, freq)))
 				freq = 0;
 		}
-	} else {
+	} else if (ssid->mode == WPAS_MODE_INFRA) {
 		freq = neg_freq;
-		if (freq < 0 ||
-		    (freq > 0 && !freq_included(channels, freq)))
-			freq = 0;
-	}
+		if (freq <= 0 || !freq_included(channels, freq)) {
+			struct os_reltime now;
+			struct wpa_bss *bss =
+				wpa_bss_get_p2p_dev_addr(wpa_s, ssid->bssid);
 
-	if (ssid->mode == WPAS_MODE_INFRA)
+			os_get_reltime(&now);
+			if (bss &&
+			    !os_reltime_expired(&now, &bss->last_update, 5) &&
+			    freq_included(channels, bss->freq))
+				freq = bss->freq;
+			else
+				freq = 0;
+		}
+
 		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq);
-
-	if (ssid->mode != WPAS_MODE_P2P_GO)
+	} else {
 		return -1;
+	}
 
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
 		return -1;
@@ -5830,13 +5746,25 @@
 
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		       const char *config_method,
-		       enum wpas_p2p_prov_disc_use use)
+		       enum wpas_p2p_prov_disc_use use,
+		       struct p2ps_provision *p2ps_prov)
 {
 	u16 config_methods;
 
+	wpa_s->global->pending_p2ps_group = 0;
 	wpa_s->p2p_fallback_to_go_neg = 0;
 	wpa_s->pending_pd_use = NORMAL_PD;
-	if (os_strncmp(config_method, "display", 7) == 0)
+	if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
+		p2ps_prov->conncap = p2ps_group_capability(
+			wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+		wpa_printf(MSG_DEBUG,
+			   "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
+			   __func__, p2ps_prov->conncap,
+			   p2ps_prov->adv_id, p2ps_prov->conncap,
+			   p2ps_prov->status, p2ps_prov->info);
+
+		config_methods = 0;
+	} else if (os_strncmp(config_method, "display", 7) == 0)
 		config_methods = WPS_CONFIG_DISPLAY;
 	else if (os_strncmp(config_method, "keypad", 6) == 0)
 		config_methods = WPS_CONFIG_KEYPAD;
@@ -5845,6 +5773,7 @@
 		config_methods = WPS_CONFIG_PUSHBUTTON;
 	else {
 		wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+		os_free(p2ps_prov);
 		return -1;
 	}
 
@@ -5865,10 +5794,12 @@
 		return 0;
 	}
 
-	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
+		os_free(p2ps_prov);
 		return -1;
+	}
 
-	return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
+	return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, p2ps_prov,
 				 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
 				 0, 1);
 }
@@ -5897,7 +5828,8 @@
 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, unsigned int search_delay)
+		  const u8 *dev_id, unsigned int search_delay,
+		  u8 seek_cnt, const char **seek_string, int freq)
 {
 	wpas_p2p_clear_pending_action_tx(wpa_s);
 	wpa_s->p2p_long_listen = 0;
@@ -5910,7 +5842,7 @@
 
 	return p2p_find(wpa_s->global->p2p, timeout, type,
 			num_req_dev_types, req_dev_types, dev_id,
-			search_delay);
+			search_delay, seek_cnt, seek_string, freq);
 }
 
 
@@ -5957,7 +5889,8 @@
 void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_stop_find_oper(wpa_s);
-	wpas_p2p_remove_pending_group_interface(wpa_s);
+	if (!wpa_s->global->pending_group_iface_for_p2ps)
+		wpas_p2p_remove_pending_group_interface(wpa_s);
 }
 
 
@@ -6167,6 +6100,12 @@
 		pref_freq = 0;
 	}
 
+	/*
+	 * Stop any find/listen operations before invitation and possibly
+	 * connection establishment.
+	 */
+	wpas_p2p_stop_find_oper(wpa_s);
+
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
 			  1, pref_freq, -1);
@@ -7047,7 +6986,7 @@
 		if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
 			continue;
 		for (i = 0; i < s->num_p2p_clients; i++) {
-			if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+			if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
 				      addr, ETH_ALEN) == 0)
 				return s; /* peer is P2P client in persistent
 					   * group */
@@ -7102,16 +7041,18 @@
 }
 
 
-static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
-					int group_added)
+static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+				       int group_added)
 {
 	struct wpa_supplicant *group = wpa_s;
+	int ret = 0;
+
 	if (wpa_s->global->p2p_group_formation)
 		group = wpa_s->global->p2p_group_formation;
 	wpa_s = wpa_s->parent;
 	offchannel_send_action_done(wpa_s);
 	if (group_added)
-		wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
+		ret = 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,
@@ -7120,11 +7061,14 @@
 			 wpa_s->p2p_pd_before_go_neg,
 			 wpa_s->p2p_go_ht40,
 			 wpa_s->p2p_go_vht);
+	return ret;
 }
 
 
 int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
 {
+	int res;
+
 	if (!wpa_s->p2p_fallback_to_go_neg ||
 	    wpa_s->p2p_in_provisioning <= 5)
 		return 0;
@@ -7134,9 +7078,11 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
 		"fallback to GO Negotiation");
-	wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+	wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
+		       "reason=GO-not-found");
+	res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
 
-	return 1;
+	return res == 1 ? 2 : 1;
 }
 
 
@@ -8085,7 +8031,7 @@
 
 	if (cand) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
-			"P2P: Update Listen channel to %u baased on operating channel",
+			"P2P: Update Listen channel to %u based on operating channel",
 			cand);
 		p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
 	}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 9f5a83b..0b9ebc0 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -15,6 +15,7 @@
 struct p2p_peer_info;
 struct p2p_channels;
 struct wps_event_fail;
+struct p2ps_provision;
 
 int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
 				  const char *conf_p2p_dev);
@@ -41,11 +42,13 @@
 enum wpas_p2p_prov_disc_use {
 	WPAS_P2P_PD_FOR_GO_NEG,
 	WPAS_P2P_PD_FOR_JOIN,
-	WPAS_P2P_PD_AUTO
+	WPAS_P2P_PD_AUTO,
+	WPAS_P2P_PD_FOR_ASP
 };
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		       const char *config_method,
-		       enum wpas_p2p_prov_disc_use use);
+		       enum wpas_p2p_prov_disc_use use,
+		       struct p2ps_provision *p2ps_prov);
 void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
 				const u8 *data, size_t data_len,
 				enum p2p_send_action_result result);
@@ -55,7 +58,8 @@
 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, unsigned int search_delay);
+		  const u8 *dev_id, unsigned int search_delay,
+		  u8 seek_cnt, const char **seek_string, int freq);
 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_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
@@ -65,6 +69,8 @@
 void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
 u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
 			const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+			    const char *svc_str, const char *info_substr);
 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,
@@ -83,6 +89,16 @@
 			      const char *service);
 int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
 			      const char *service);
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s, int auto_accept,
+			     u32 adv_id, const char *adv_str, u8 svc_state,
+			     u16 config_methods, const char *svc_info);
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id);
+void wpas_p2p_service_flush_asp(struct wpa_supplicant *wpa_s);
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id);
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+		     u16 update_indic, const u8 *tlvs, size_t tlvs_len);
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+		      const u8 *tlvs, size_t tlvs_len);
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c
new file mode 100644
index 0000000..f4aa3e0
--- /dev/null
+++ b/wpa_supplicant/p2p_supplicant_sd.c
@@ -0,0 +1,1272 @@
+/*
+ * wpa_supplicant - P2P service discovery
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "p2p/p2p.h"
+#include "wpa_supplicant_i.h"
+#include "notify.h"
+#include "p2p_supplicant.h"
+
+
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+				       u8 **spos, const u8 *end)
+{
+	while (*spos < end) {
+		u8 val = ((*spos)[0] & 0xc0) >> 6;
+		int len;
+
+		if (val == 1 || val == 2) {
+			/* These are reserved values in RFC 1035 */
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence starting with 0x%x", val);
+			return -1;
+		}
+
+		if (val == 3) {
+			u16 offset;
+			u8 *spos_tmp;
+
+			/* Offset */
+			if (*spos + 2 > end) {
+				wpa_printf(MSG_DEBUG, "P2P: No room for full "
+					   "DNS offset field");
+				return -1;
+			}
+
+			offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+			if (offset >= *spos - start) {
+				wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+					   "pointer offset %u", offset);
+				return -1;
+			}
+
+			(*spos) += 2;
+			spos_tmp = start + offset;
+			return p2p_sd_dns_uncompress_label(upos, uend, start,
+							   &spos_tmp,
+							   *spos - 2);
+		}
+
+		/* Label */
+		len = (*spos)[0] & 0x3f;
+		if (len == 0)
+			return 0;
+
+		(*spos)++;
+		if (*spos + len > end) {
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence - no room for label with length "
+				   "%u", len);
+			return -1;
+		}
+
+		if (*upos + len + 2 > uend)
+			return -2;
+
+		os_memcpy(*upos, *spos, len);
+		*spos += len;
+		*upos += len;
+		(*upos)[0] = '.';
+		(*upos)++;
+		(*upos)[0] = '\0';
+	}
+
+	return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+				 size_t msg_len, size_t offset)
+{
+	/* 27-octet in-memory packet from P2P specification */
+	const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+		"\x04_udp\xC0\x11\x00\x0C\x00\x01";
+	u8 *tmp, *end, *spos;
+	char *upos, *uend;
+	int ret = 0;
+
+	if (buf_len < 2)
+		return -1;
+	if (offset > msg_len)
+		return -1;
+
+	tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+	if (tmp == NULL)
+		return -1;
+	spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+	end = spos + msg_len;
+	spos += offset;
+
+	os_memset(tmp, 0, DNS_HEADER_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+	upos = buf;
+	uend = buf + buf_len;
+
+	ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+	if (ret) {
+		os_free(tmp);
+		return ret;
+	}
+
+	if (upos == buf) {
+		upos[0] = '.';
+		upos[1] = '\0';
+	} else if (upos[-1] == '.')
+		upos[-1] = '\0';
+
+	os_free(tmp);
+	return 0;
+}
+
+
+static struct p2p_srv_bonjour *
+wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
+			     const struct wpabuf *query)
+{
+	struct p2p_srv_bonjour *bsrv;
+	size_t len;
+
+	len = wpabuf_len(query);
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (len == wpabuf_len(bsrv->query) &&
+		    os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
+			      len) == 0)
+			return bsrv;
+	}
+	return NULL;
+}
+
+
+static struct p2p_srv_upnp *
+wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			  const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (version == usrv->version &&
+		    os_strcmp(service, usrv->service) == 0)
+			return usrv;
+	}
+	return NULL;
+}
+
+
+static void wpas_sd_add_empty(struct wpabuf *resp, u8 srv_proto,
+			      u8 srv_trans_id, u8 status)
+{
+	u8 *len_pos;
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, srv_proto);
+	wpabuf_put_u8(resp, srv_trans_id);
+	/* Status Code */
+	wpabuf_put_u8(resp, status);
+	/* Response Data: empty */
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+					u8 srv_trans_id)
+{
+	wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+			  P2P_SD_PROTO_NOT_AVAILABLE);
+}
+
+
+static void wpas_sd_add_bad_request(struct wpabuf *resp, u8 srv_proto,
+				    u8 srv_trans_id)
+{
+	wpas_sd_add_empty(resp, srv_proto, srv_trans_id, P2P_SD_BAD_REQUEST);
+}
+
+
+static void wpas_sd_add_not_found(struct wpabuf *resp, u8 srv_proto,
+				  u8 srv_trans_id)
+{
+	wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+			  P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+}
+
+
+static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
+				struct wpabuf *resp, u8 srv_trans_id)
+{
+	struct p2p_srv_bonjour *bsrv;
+	u8 *len_pos;
+
+	wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+		return;
+	}
+
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (wpabuf_tailroom(resp) <
+		    5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
+			return;
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+				  wpabuf_head(bsrv->resp),
+				  wpabuf_len(bsrv->resp));
+		/* Response Data */
+		wpabuf_put_buf(resp, bsrv->query); /* Key */
+		wpabuf_put_buf(resp, bsrv->resp); /* Value */
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+			       size_t query_len)
+{
+	char str_rx[256], str_srv[256];
+
+	if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+		return 0; /* Too short to include DNS Type and Version */
+	if (os_memcmp(query + query_len - 3,
+		      wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+		      3) != 0)
+		return 0; /* Mismatch in DNS Type or Version */
+	if (query_len == wpabuf_len(bsrv->query) &&
+	    os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+		return 1; /* Binary match */
+
+	if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+				  0))
+		return 0; /* Failed to uncompress query */
+	if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+				  wpabuf_head(bsrv->query),
+				  wpabuf_len(bsrv->query) - 3, 0))
+		return 0; /* Failed to uncompress service */
+
+	return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
+static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
+				struct wpabuf *resp, u8 srv_trans_id,
+				const u8 *query, size_t query_len)
+{
+	struct p2p_srv_bonjour *bsrv;
+	u8 *len_pos;
+	int matches = 0;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
+			  query, query_len);
+	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len == 0) {
+		wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+		return;
+	}
+
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (!match_bonjour_query(bsrv, query, query_len))
+			continue;
+
+		if (wpabuf_tailroom(resp) <
+		    5 + query_len + wpabuf_len(bsrv->resp))
+			return;
+
+		matches++;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+				  wpabuf_head(bsrv->resp),
+				  wpabuf_len(bsrv->resp));
+
+		/* Response Data */
+		wpabuf_put_data(resp, query, query_len); /* Key */
+		wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+	}
+
+	if (matches == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
+			   "available");
+		if (wpabuf_tailroom(resp) < 5)
+			return;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+		/* Response Data: empty */
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
+			     struct wpabuf *resp, u8 srv_trans_id)
+{
+	struct p2p_srv_upnp *usrv;
+	u8 *len_pos;
+
+	wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+		return;
+	}
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
+			return;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_UPNP);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		/* Response Data */
+		wpabuf_put_u8(resp, usrv->version);
+		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+			   usrv->service);
+		wpabuf_put_str(resp, usrv->service);
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
+			     struct wpabuf *resp, u8 srv_trans_id,
+			     const u8 *query, size_t query_len)
+{
+	struct p2p_srv_upnp *usrv;
+	u8 *len_pos;
+	u8 version;
+	char *str;
+	int count = 0;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
+			  query, query_len);
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len == 0) {
+		wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+		return;
+	}
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, P2P_SERV_UPNP);
+	wpabuf_put_u8(resp, srv_trans_id);
+
+	version = query[0];
+	str = os_malloc(query_len);
+	if (str == NULL)
+		return;
+	os_memcpy(str, query + 1, query_len - 1);
+	str[query_len - 1] = '\0';
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (version != usrv->version)
+			continue;
+
+		if (os_strcmp(str, "ssdp:all") != 0 &&
+		    os_strstr(usrv->service, str) == NULL)
+			continue;
+
+		if (wpabuf_tailroom(resp) < 2)
+			break;
+		if (count == 0) {
+			/* Status Code */
+			wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+			/* Response Data */
+			wpabuf_put_u8(resp, version);
+		} else
+			wpabuf_put_u8(resp, ',');
+
+		count++;
+
+		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+			   usrv->service);
+		if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
+			break;
+		wpabuf_put_str(resp, usrv->service);
+	}
+	os_free(str);
+
+	if (count == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
+			   "available");
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+		/* Response Data: empty */
+	}
+
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
+			    struct wpabuf *resp, u8 srv_trans_id,
+			    const u8 *query, size_t query_len)
+{
+	const u8 *pos;
+	u8 role;
+	u8 *len_pos;
+
+	wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
+
+	if (!wpa_s->global->wifi_display) {
+		wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len < 1) {
+		wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
+			   "Role");
+		return;
+	}
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	pos = query;
+	role = *pos++;
+	wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
+
+	/* TODO: role specific handling */
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
+	wpabuf_put_u8(resp, srv_trans_id);
+	wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
+
+	while (pos < query + query_len) {
+		if (*pos < MAX_WFD_SUBELEMS &&
+		    wpa_s->global->wfd_subelem[*pos] &&
+		    wpabuf_tailroom(resp) >=
+		    wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
+			wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
+				   "subelement %u", *pos);
+			wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
+		}
+		pos++;
+	}
+
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+static int find_p2ps_substr(struct p2ps_advertisement *adv_data,
+			    const u8 *needle, size_t needle_len)
+{
+	const u8 *haystack = (const u8 *) adv_data->svc_info;
+	size_t haystack_len, i;
+
+	/* Allow search term to be empty */
+	if (!needle || !needle_len)
+		return 1;
+
+	if (!haystack)
+		return 0;
+
+	haystack_len = os_strlen(adv_data->svc_info);
+	for (i = 0; i < haystack_len; i++) {
+		if (haystack_len - i < needle_len)
+			break;
+		if (os_memcmp(haystack + i, needle, needle_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void wpas_sd_req_asp(struct wpa_supplicant *wpa_s,
+			    struct wpabuf *resp, u8 srv_trans_id,
+			    const u8 *query, size_t query_len)
+{
+	struct p2ps_advertisement *adv_data;
+	const u8 *svc = &query[1];
+	const u8 *info = NULL;
+	size_t svc_len = query[0];
+	size_t info_len = 0;
+	int prefix = 0;
+	u8 *count_pos = NULL;
+	u8 *len_pos = NULL;
+
+	wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
+
+	if (!wpa_s->global->p2p) {
+		wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
+		return;
+	}
+
+	/* Info block is optional */
+	if (svc_len + 1 < query_len) {
+		info = &svc[svc_len];
+		info_len = *info++;
+	}
+
+	/* Range check length of svc string and info block */
+	if (svc_len + (info_len ? info_len + 2 : 1) > query_len) {
+		wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+		wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+		return;
+	}
+
+	/* Detect and correct for prefix search */
+	if (svc_len && svc[svc_len - 1] == '*') {
+		prefix = 1;
+		svc_len--;
+	}
+
+	for (adv_data = p2p_get_p2ps_adv_list(wpa_s->global->p2p);
+	     adv_data; adv_data = adv_data->next) {
+		/* If not a prefix match, reject length mismatches */
+		if (!prefix && svc_len != os_strlen(adv_data->svc_name))
+			continue;
+
+		/* Search each service for request */
+		if (os_memcmp(adv_data->svc_name, svc, svc_len) == 0 &&
+		    find_p2ps_substr(adv_data, info, info_len)) {
+			size_t len = os_strlen(adv_data->svc_name);
+			size_t svc_info_len = 0;
+
+			if (adv_data->svc_info)
+				svc_info_len = os_strlen(adv_data->svc_info);
+
+			if (len > 0xff || svc_info_len > 0xffff)
+				return;
+
+			/* Length & Count to be filled as we go */
+			if (!len_pos && !count_pos) {
+				if (wpabuf_tailroom(resp) <
+				    len + svc_info_len + 16)
+					return;
+
+				len_pos = wpabuf_put(resp, 2);
+				wpabuf_put_u8(resp, P2P_SERV_P2PS);
+				wpabuf_put_u8(resp, srv_trans_id);
+				/* Status Code */
+				wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+				count_pos = wpabuf_put(resp, 1);
+				*count_pos = 0;
+			} else if (wpabuf_tailroom(resp) <
+				   len + svc_info_len + 10)
+				return;
+
+			if (svc_info_len) {
+				wpa_printf(MSG_DEBUG,
+					   "P2P: Add Svc: %s info: %s",
+					   adv_data->svc_name,
+					   adv_data->svc_info);
+			} else {
+				wpa_printf(MSG_DEBUG, "P2P: Add Svc: %s",
+					   adv_data->svc_name);
+			}
+
+			/* Advertisement ID */
+			wpabuf_put_le32(resp, adv_data->id);
+
+			/* Config Methods */
+			wpabuf_put_be16(resp, adv_data->config_methods);
+
+			/* Service Name */
+			wpabuf_put_u8(resp, (u8) len);
+			wpabuf_put_data(resp, adv_data->svc_name, len);
+
+			/* Service State */
+			wpabuf_put_u8(resp, adv_data->state);
+
+			/* Service Information */
+			wpabuf_put_le16(resp, (u16) svc_info_len);
+			wpabuf_put_data(resp, adv_data->svc_info, svc_info_len);
+
+			/* Update length and count */
+			(*count_pos)++;
+			WPA_PUT_LE16(len_pos,
+				     (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+		}
+	}
+
+	/* Return error if no matching svc found */
+	if (count_pos == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: ASP service not found");
+		wpas_sd_add_not_found(resp, P2P_SERV_P2PS, srv_trans_id);
+	}
+}
+
+
+static void wpas_sd_all_asp(struct wpa_supplicant *wpa_s,
+			    struct wpabuf *resp, u8 srv_trans_id)
+{
+	/* Query data to add all P2PS advertisements:
+	 *  - Service name length: 1
+	 *  - Service name: '*'
+	 *  - Service Information Request Length: 0
+	 */
+	const u8 q[] = { 1, (const u8) '*', 0 };
+
+	if (p2p_get_p2ps_adv_list(wpa_s->global->p2p))
+		wpas_sd_req_asp(wpa_s, resp, srv_trans_id, q, sizeof(q));
+}
+
+
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+		     u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos = tlvs;
+	const u8 *end = tlvs + tlvs_len;
+	const u8 *tlv_end;
+	u16 slen;
+	struct wpabuf *resp;
+	u8 srv_proto, srv_trans_id;
+	size_t buf_len;
+	char *buf;
+
+	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
+		    tlvs, tlvs_len);
+	buf_len = 2 * tlvs_len + 1;
+	buf = os_malloc(buf_len);
+	if (buf) {
+		wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+		wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
+			     MACSTR " %u %u %s",
+			     freq, MAC2STR(sa), dialog_token, update_indic,
+			     buf);
+		os_free(buf);
+	}
+
+	if (wpa_s->p2p_sd_over_ctrl_iface) {
+		wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					   update_indic, tlvs, tlvs_len);
+		return; /* to be processed by an external program */
+	}
+
+	resp = wpabuf_alloc(10000);
+	if (resp == NULL)
+		return;
+
+	while (pos + 1 < end) {
+		wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
+		slen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (pos + slen > end || slen < 2) {
+			wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
+				   "length");
+			wpabuf_free(resp);
+			return;
+		}
+		tlv_end = pos + slen;
+
+		srv_proto = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+			   srv_proto);
+		srv_trans_id = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+			   srv_trans_id);
+
+		wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
+			    pos, tlv_end - pos);
+
+
+		if (wpa_s->force_long_sd) {
+			wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
+				   "response");
+			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_asp(wpa_s, resp, srv_trans_id);
+			goto done;
+		}
+
+		switch (srv_proto) {
+		case P2P_SERV_ALL_SERVICES:
+			wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
+				   "for all services");
+			if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
+			    dl_list_empty(&wpa_s->global->p2p_srv_bonjour) &&
+			    !p2p_get_p2ps_adv_list(wpa_s->global->p2p)) {
+				wpa_printf(MSG_DEBUG, "P2P: No service "
+					   "discovery protocols available");
+				wpas_sd_add_proto_not_avail(
+					resp, P2P_SERV_ALL_SERVICES,
+					srv_trans_id);
+				break;
+			}
+			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_asp(wpa_s, resp, srv_trans_id);
+			break;
+		case P2P_SERV_BONJOUR:
+			wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
+					    pos, tlv_end - pos);
+			break;
+		case P2P_SERV_UPNP:
+			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 */
+		case P2P_SERV_P2PS:
+			wpas_sd_req_asp(wpa_s, resp, srv_trans_id,
+					pos, tlv_end - pos);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
+				   "protocol %u", srv_proto);
+			wpas_sd_add_proto_not_avail(resp, srv_proto,
+						    srv_trans_id);
+			break;
+		}
+
+		pos = tlv_end;
+	}
+
+done:
+	wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+				   update_indic, tlvs, tlvs_len);
+
+	wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
+
+	wpabuf_free(resp);
+}
+
+
+static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
+				       const u8 *sa, u8 srv_trans_id,
+				       const u8 *pos, const u8 *tlv_end)
+{
+	u8 left = *pos++;
+	u32 adv_id;
+	u8 svc_status;
+	u16 config_methods;
+	char svc_str[256];
+
+	while (left-- && pos < tlv_end) {
+		char *buf = NULL;
+		size_t buf_len;
+		u8 svc_len;
+
+		/* Sanity check fixed length+svc_str */
+		if (pos + 6 >= tlv_end)
+			break;
+		svc_len = pos[6];
+		if (pos + svc_len + 10 > tlv_end)
+			break;
+
+		/* Advertisement ID */
+		adv_id = WPA_GET_LE32(pos);
+		pos += sizeof(u32);
+
+		/* Config Methods */
+		config_methods = WPA_GET_BE16(pos);
+		pos += sizeof(u16);
+
+		/* Service Name */
+		pos++; /* svc_len */
+		os_memcpy(svc_str, pos, svc_len);
+		svc_str[svc_len] = '\0';
+		pos += svc_len;
+
+		/* Service Status */
+		svc_status = *pos++;
+
+		/* Service Information Length */
+		buf_len = WPA_GET_LE16(pos);
+		pos += sizeof(u16);
+
+		/* Sanity check buffer length */
+		if (buf_len > (unsigned int) (tlv_end - pos))
+			break;
+
+		if (buf_len) {
+			buf = os_zalloc(2 * buf_len + 1);
+			if (buf) {
+				utf8_escape((const char *) pos, buf_len, buf,
+					    2 * buf_len + 1);
+			}
+		}
+
+		pos += buf_len;
+
+		if (buf) {
+			wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+				       MACSTR " %x %x %x %x %s '%s'",
+				       MAC2STR(sa), srv_trans_id, adv_id,
+				       svc_status, config_methods, svc_str,
+				       buf);
+			os_free(buf);
+		} else {
+			wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+				       MACSTR " %x %x %x %x %s",
+				       MAC2STR(sa), srv_trans_id, adv_id,
+				       svc_status, config_methods, svc_str);
+		}
+	}
+}
+
+
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+		      const u8 *tlvs, size_t tlvs_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos = tlvs;
+	const u8 *end = tlvs + tlvs_len;
+	const u8 *tlv_end;
+	u16 slen;
+	size_t buf_len;
+	char *buf;
+
+	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
+		    tlvs, tlvs_len);
+	if (tlvs_len > 1500) {
+		/* TODO: better way for handling this */
+		wpa_msg_ctrl(wpa_s, MSG_INFO,
+			     P2P_EVENT_SERV_DISC_RESP MACSTR
+			     " %u <long response: %u bytes>",
+			     MAC2STR(sa), update_indic,
+			     (unsigned int) tlvs_len);
+	} else {
+		buf_len = 2 * tlvs_len + 1;
+		buf = os_malloc(buf_len);
+		if (buf) {
+			wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+			wpa_msg_ctrl(wpa_s, MSG_INFO,
+				     P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
+				     MAC2STR(sa), update_indic, buf);
+			os_free(buf);
+		}
+	}
+
+	while (pos < end) {
+		u8 srv_proto, srv_trans_id, status;
+
+		wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
+		slen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (pos + slen > end || slen < 3) {
+			wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
+				   "length");
+			return;
+		}
+		tlv_end = pos + slen;
+
+		srv_proto = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+			   srv_proto);
+		srv_trans_id = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+			   srv_trans_id);
+		status = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
+			   status);
+
+		wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
+			    pos, tlv_end - pos);
+
+		if (srv_proto == P2P_SERV_P2PS && pos < tlv_end) {
+			wpas_sd_p2ps_serv_response(wpa_s, sa, srv_trans_id,
+						   pos, tlv_end);
+		}
+
+		pos = tlv_end;
+	}
+
+	wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
+}
+
+
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+	return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query)
+{
+	struct wpabuf *tlvs;
+	u64 ret;
+
+	tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
+	if (tlvs == NULL)
+		return 0;
+	wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
+	wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
+	wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
+	wpabuf_put_u8(tlvs, version);
+	wpabuf_put_str(tlvs, query);
+	ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+	wpabuf_free(tlvs);
+	return ret;
+}
+
+
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+			    const char *svc_str, const char *info_substr)
+{
+	struct wpabuf *tlvs;
+	size_t plen, svc_len, substr_len = 0;
+	u64 ret;
+
+	svc_len = os_strlen(svc_str);
+	if (info_substr)
+		substr_len = os_strlen(info_substr);
+
+	if (svc_len > 0xff || substr_len > 0xff)
+		return 0;
+
+	plen = 1 + 1 + 1 + svc_len + 1 + substr_len;
+	tlvs = wpabuf_alloc(2 + plen);
+	if (tlvs == NULL)
+		return 0;
+
+	wpabuf_put_le16(tlvs, plen);
+	wpabuf_put_u8(tlvs, P2P_SERV_P2PS);
+	wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+	wpabuf_put_u8(tlvs, (u8) svc_len); /* Service String Length */
+	wpabuf_put_data(tlvs, svc_str, svc_len);
+	wpabuf_put_u8(tlvs, (u8) substr_len); /* Info Substring Length */
+	wpabuf_put_data(tlvs, info_substr, substr_len);
+	ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+	wpabuf_free(tlvs);
+
+	return ret;
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
+				   const struct wpabuf *tlvs)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+	return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+				const char *subelems)
+{
+	u8 *len;
+	const char *pos;
+	int val;
+	int count = 0;
+
+	len = wpabuf_put(tlvs, 2);
+	wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
+	wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+
+	wpabuf_put_u8(tlvs, role);
+
+	pos = subelems;
+	while (*pos) {
+		val = atoi(pos);
+		if (val >= 0 && val < 256) {
+			wpabuf_put_u8(tlvs, val);
+			count++;
+			if (count == MAX_WFD_SD_SUBELEMS)
+				break;
+		}
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
+}
+
+
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, const char *role)
+{
+	struct wpabuf *tlvs;
+	u64 ret;
+	const char *subelems;
+	u8 id = 1;
+
+	subelems = os_strchr(role, ' ');
+	if (subelems == NULL)
+		return 0;
+	subelems++;
+
+	tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
+	if (tlvs == NULL)
+		return 0;
+
+	if (os_strstr(role, "[source]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
+	if (os_strstr(role, "[pri-sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
+	if (os_strstr(role, "[sec-sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
+	if (os_strstr(role, "[source+sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
+
+	ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
+	wpabuf_free(tlvs);
+	return ret;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+	return p2p_sd_cancel_request(wpa_s->global->p2p,
+				     (void *) (uintptr_t) req);
+}
+
+
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+			  const u8 *dst, u8 dialog_token,
+			  const struct wpabuf *resp_tlvs)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+	p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
+			resp_tlvs);
+}
+
+
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->global->p2p)
+		p2p_sd_service_update(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
+{
+	dl_list_del(&bsrv->list);
+	wpabuf_free(bsrv->query);
+	wpabuf_free(bsrv->resp);
+	os_free(bsrv);
+}
+
+
+static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
+{
+	dl_list_del(&usrv->list);
+	os_free(usrv->service);
+	os_free(usrv);
+}
+
+
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
+{
+	struct p2p_srv_bonjour *bsrv, *bn;
+	struct p2p_srv_upnp *usrv, *un;
+
+	dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
+			      struct p2p_srv_bonjour, list)
+		wpas_p2p_srv_bonjour_free(bsrv);
+
+	dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
+			      struct p2p_srv_upnp, list)
+		wpas_p2p_srv_upnp_free(usrv);
+
+	wpas_p2p_service_flush_asp(wpa_s);
+	wpas_p2p_sd_service_update(wpa_s);
+}
+
+
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+	if (adv_id == 0)
+		return 1;
+
+	if (p2p_service_p2ps_id(wpa_s->global->p2p, adv_id))
+		return 1;
+
+	return 0;
+}
+
+
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+	int ret;
+
+	ret = p2p_service_del_asp(wpa_s->global->p2p, adv_id);
+	if (ret == 0)
+		wpas_p2p_sd_service_update(wpa_s);
+	return ret;
+}
+
+
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s,
+			     int auto_accept, u32 adv_id,
+			     const char *adv_str, u8 svc_state,
+			     u16 config_methods, const char *svc_info)
+{
+	int ret;
+
+	ret = p2p_service_add_asp(wpa_s->global->p2p, auto_accept, adv_id,
+				  adv_str, svc_state, config_methods,
+				  svc_info);
+	if (ret == 0)
+		wpas_p2p_sd_service_update(wpa_s);
+	return ret;
+}
+
+
+void wpas_p2p_service_flush_asp(struct wpa_supplicant *wpa_s)
+{
+	p2p_service_flush_asp(wpa_s->global->p2p);
+}
+
+
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+				 struct wpabuf *query, struct wpabuf *resp)
+{
+	struct p2p_srv_bonjour *bsrv;
+
+	bsrv = os_zalloc(sizeof(*bsrv));
+	if (bsrv == NULL)
+		return -1;
+	bsrv->query = query;
+	bsrv->resp = resp;
+	dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
+
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *query)
+{
+	struct p2p_srv_bonjour *bsrv;
+
+	bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
+	if (bsrv == NULL)
+		return -1;
+	wpas_p2p_srv_bonjour_free(bsrv);
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	if (wpas_p2p_service_get_upnp(wpa_s, version, service))
+		return 0; /* Already listed */
+	usrv = os_zalloc(sizeof(*usrv));
+	if (usrv == NULL)
+		return -1;
+	usrv->version = version;
+	usrv->service = os_strdup(service);
+	if (usrv->service == NULL) {
+		os_free(usrv);
+		return -1;
+	}
+	dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
+
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
+	if (usrv == NULL)
+		return -1;
+	wpas_p2p_srv_upnp_free(usrv);
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b303760..3c6b2c7 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -96,6 +96,10 @@
 {
 	struct wpa_ssid *ssid = wpa_s->conf->ssid;
 	int count = 0, disabled = 0;
+
+	if (wpa_s->p2p_mgmt)
+		return 0; /* no normal network profiles on p2p_mgmt interface */
+
 	while (ssid) {
 		if (!wpas_network_disabled(wpa_s, ssid))
 			count++;
@@ -168,17 +172,34 @@
 
 	wpa_supplicant_notify_scanning(wpa_s, 1);
 
-	if (wpa_s->clear_driver_scan_cache)
+	if (wpa_s->clear_driver_scan_cache) {
+		wpa_printf(MSG_DEBUG,
+			   "Request driver to clear scan cache due to local BSS flush");
 		params->only_new_results = 1;
+	}
 	ret = wpa_drv_scan(wpa_s, params);
 	wpa_scan_free_params(params);
 	work->ctx = NULL;
 	if (ret) {
+		int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ;
+
+		if (wpa_s->disconnected)
+			retry = 0;
+
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 		wpas_notify_scan_done(wpa_s, 0);
-		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d",
-			     ret);
+		if (wpa_s->wpa_state == WPA_SCANNING)
+			wpa_supplicant_set_state(wpa_s,
+						 wpa_s->scan_prev_wpa_state);
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d%s",
+			ret, retry ? " retry=1" : "");
 		radio_work_done(work);
+
+		if (retry) {
+			/* Restore scan_req since we will try to scan again */
+			wpa_s->scan_req = wpa_s->last_scan_req;
+			wpa_supplicant_req_scan(wpa_s, 1, 0);
+		}
 		return;
 	}
 
@@ -397,22 +418,6 @@
 static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
 					   struct wpabuf *buf)
 {
-	if (wpa_s->conf->interworking == 0)
-		return;
-
-	wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
-	wpabuf_put_u8(buf, 6);
-	wpabuf_put_u8(buf, 0x00);
-	wpabuf_put_u8(buf, 0x00);
-	wpabuf_put_u8(buf, 0x00);
-	wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
-	wpabuf_put_u8(buf, 0x00);
-#ifdef CONFIG_HS20
-	wpabuf_put_u8(buf, 0x40); /* Bit 46 - WNM-Notification */
-#else /* CONFIG_HS20 */
-	wpabuf_put_u8(buf, 0x00);
-#endif /* CONFIG_HS20 */
-
 	wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
 	wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
 		      1 + ETH_ALEN);
@@ -427,11 +432,19 @@
 static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
 	struct wpabuf *extra_ie = NULL;
+	u8 ext_capab[18];
+	int ext_capab_len;
 #ifdef CONFIG_WPS
 	int wps = 0;
 	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
 #endif /* CONFIG_WPS */
 
+	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+					     sizeof(ext_capab));
+	if (ext_capab_len > 0 &&
+	    wpabuf_resize(&extra_ie, ext_capab_len) == 0)
+		wpabuf_put_data(extra_ie, ext_capab, ext_capab_len);
+
 #ifdef CONFIG_INTERWORKING
 	if (wpa_s->conf->interworking &&
 	    wpabuf_resize(&extra_ie, 100) == 0)
@@ -610,7 +623,7 @@
 	struct wpa_driver_scan_params params;
 	struct wpa_driver_scan_params *scan_params;
 	size_t max_ssids;
-	enum wpa_states prev_state;
+	int connect_without_scan = 0;
 
 	if (wpa_s->pno || wpa_s->pno_sched_pending) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
@@ -658,8 +671,20 @@
 		return;
 	}
 
+	ssid = NULL;
+	if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
+	    wpa_s->connect_without_scan) {
+		connect_without_scan = 1;
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (ssid == wpa_s->connect_without_scan)
+				break;
+		}
+	}
+
 	p2p_in_prog = wpas_p2p_in_progress(wpa_s);
-	if (p2p_in_prog && p2p_in_prog != 2) {
+	if (p2p_in_prog && p2p_in_prog != 2 &&
+	    (!ssid ||
+	     (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
 		wpa_supplicant_req_scan(wpa_s, 5, 0);
 		return;
@@ -676,9 +701,19 @@
 	wpa_s->last_scan_req = wpa_s->scan_req;
 	wpa_s->scan_req = NORMAL_SCAN_REQ;
 
+	if (connect_without_scan) {
+		wpa_s->connect_without_scan = NULL;
+		if (ssid) {
+			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+				   "without scan step");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			return;
+		}
+	}
+
 	os_memset(&params, 0, sizeof(params));
 
-	prev_state = wpa_s->wpa_state;
+	wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
 	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
 	    wpa_s->wpa_state == WPA_INACTIVE)
 		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
@@ -691,24 +726,9 @@
 		goto scan;
 	}
 
-	if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
-	    wpa_s->connect_without_scan) {
-		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-			if (ssid == wpa_s->connect_without_scan)
-				break;
-		}
-		wpa_s->connect_without_scan = NULL;
-		if (ssid) {
-			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
-				   "without scan step");
-			wpa_supplicant_associate(wpa_s, NULL, ssid);
-			return;
-		}
-	}
-
 #ifdef CONFIG_P2P
 	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
-	    wpa_s->go_params) {
+	    wpa_s->go_params && !wpa_s->conf->passive_scan) {
 		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
 			   wpa_s->p2p_in_provisioning,
 			   wpa_s->show_group_started);
@@ -862,6 +882,9 @@
 	} else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
 		   wpa_s->manual_scan_passive && params.num_ssids == 0) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
+	} else if (wpa_s->conf->passive_scan) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Use passive scan based on configuration");
 	} else {
 		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
 		params.num_ssids++;
@@ -876,8 +899,11 @@
 	extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
 	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
-	    wpa_s->manual_scan_only_new)
+	    wpa_s->manual_scan_only_new) {
+		wpa_printf(MSG_DEBUG,
+			   "Request driver to clear scan cache due to manual only_new=1 scan");
 		params.only_new_results = 1;
+	}
 
 	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
 	    wpa_s->manual_scan_freqs) {
@@ -938,6 +964,14 @@
 	}
 #endif /* CONFIG_P2P */
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_scan) {
+			params.mac_addr = wpa_s->mac_addr_scan;
+			params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
+		}
+	}
+
 	scan_params = &params;
 
 scan:
@@ -987,13 +1021,17 @@
 
 	if (ret) {
 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
-		if (prev_state != wpa_s->wpa_state)
-			wpa_supplicant_set_state(wpa_s, prev_state);
+		if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s,
+						 wpa_s->scan_prev_wpa_state);
 		/* Restore scan_req since we will try to scan again */
 		wpa_s->scan_req = wpa_s->last_scan_req;
 		wpa_supplicant_req_scan(wpa_s, 1, 0);
 	} else {
 		wpa_s->scan_for_connection = 0;
+#ifdef CONFIG_INTERWORKING
+		wpa_s->interworking_fast_assoc_tried = 0;
+#endif /* CONFIG_INTERWORKING */
 	}
 }
 
@@ -1032,8 +1070,17 @@
  */
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 {
-	int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
-					NULL);
+	int res;
+
+	if (wpa_s->p2p_mgmt) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
+			sec, usec);
+		return;
+	}
+
+	res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+				    NULL);
 	if (res == 1) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
 			sec, usec);
@@ -1281,6 +1328,15 @@
 
 	wpa_setband_scan_freqs(wpa_s, scan_params);
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_sched_scan) {
+			params.mac_addr = wpa_s->mac_addr_sched_scan;
+			params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
+				ETH_ALEN;
+		}
+	}
+
 	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
 					      wpa_s->sched_scan_interval);
 	wpabuf_free(extra_ie);
@@ -1551,18 +1607,19 @@
  */
 #define GREAT_SNR 30
 
+#define IS_5GHZ(n) (n > 4000)
+
 /* Compare function for sorting scan results. Return >0 if @b is considered
  * better. */
 static int wpa_scan_result_compar(const void *a, const void *b)
 {
-#define IS_5GHZ(n) (n > 4000)
 #define MIN(a,b) a < b ? a : b
 	struct wpa_scan_res **_wa = (void *) a;
 	struct wpa_scan_res **_wb = (void *) b;
 	struct wpa_scan_res *wa = *_wa;
 	struct wpa_scan_res *wb = *_wb;
-	int wpa_a, wpa_b, maxrate_a, maxrate_b;
-	int snr_a, snr_b;
+	int wpa_a, wpa_b;
+	int snr_a, snr_b, snr_a_full, snr_b_full;
 
 	/* WPA/WPA2 support preferred */
 	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -1583,37 +1640,34 @@
 	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
 		return -1;
 
-	if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
-	    !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
-		snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
-		snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+	if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
+		snr_a_full = wa->snr;
+		snr_a = MIN(wa->snr, GREAT_SNR);
+		snr_b_full = wb->snr;
+		snr_b = MIN(wa->snr, GREAT_SNR);
 	} else {
-		/* Not suitable information to calculate SNR, so use level */
-		snr_a = wa->level;
-		snr_b = wb->level;
+		/* Level is not in dBm, so we can't calculate
+		 * SNR. Just use raw level (units unknown). */
+		snr_a = snr_a_full = wa->level;
+		snr_b = snr_b_full = wb->level;
 	}
 
-	/* best/max rate preferred if SNR close enough */
-        if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+	/* if SNR is close, decide by max rate or frequency band */
+	if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
 	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
-		maxrate_a = wpa_scan_get_max_rate(wa);
-		maxrate_b = wpa_scan_get_max_rate(wb);
-		if (maxrate_a != maxrate_b)
-			return maxrate_b - maxrate_a;
+		if (wa->est_throughput != wb->est_throughput)
+			return wb->est_throughput - wa->est_throughput;
 		if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
 			return IS_5GHZ(wa->freq) ? -1 : 1;
 	}
 
-	/* use freq for channel preference */
-
 	/* all things being equal, use SNR; if SNRs are
 	 * identical, use quality values since some drivers may only report
 	 * that value and leave the signal level zero */
-	if (snr_b == snr_a)
+	if (snr_b_full == snr_a_full)
 		return wb->qual - wa->qual;
-	return snr_b - snr_a;
+	return snr_b_full - snr_a_full;
 #undef MIN
-#undef IS_5GHZ
 }
 
 
@@ -1678,21 +1732,22 @@
 	for (i = 0; i < scan_res->num; i++) {
 		struct wpa_scan_res *r = scan_res->res[i];
 		u8 *pos;
-		if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
-		    == WPA_SCAN_LEVEL_DBM) {
-			int snr = r->level - r->noise;
+		if (r->flags & WPA_SCAN_LEVEL_DBM) {
+			int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
+
 			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
-				   "noise=%d level=%d snr=%d%s flags=0x%x "
-				   "age=%u",
+				   "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
 				   MAC2STR(r->bssid), r->freq, r->qual,
-				   r->noise, r->level, snr,
-				   snr >= GREAT_SNR ? "*" : "", r->flags,
-				   r->age);
+				   r->noise, noise_valid ? "" : "~", r->level,
+				   r->snr, r->snr >= GREAT_SNR ? "*" : "",
+				   r->flags,
+				   r->age, r->est_throughput);
 		} else {
 			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
-				   "noise=%d level=%d flags=0x%x age=%u",
+				   "noise=%d level=%d flags=0x%x age=%u est=%u",
 				   MAC2STR(r->bssid), r->freq, r->qual,
-				   r->noise, r->level, r->flags, r->age);
+				   r->noise, r->level, r->flags, r->age,
+				   r->est_throughput);
 		}
 		pos = (u8 *) (r + 1);
 		if (r->ie_len)
@@ -1759,6 +1814,188 @@
 }
 
 
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurments. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+
+static void scan_snr(struct wpa_scan_res *res)
+{
+	if (res->flags & WPA_SCAN_NOISE_INVALID) {
+		res->noise = IS_5GHZ(res->freq) ?
+			DEFAULT_NOISE_FLOOR_5GHZ :
+			DEFAULT_NOISE_FLOOR_2GHZ;
+	}
+
+	if (res->flags & WPA_SCAN_LEVEL_DBM) {
+		res->snr = res->level - res->noise;
+	} else {
+		/* Level is not in dBm, so we can't calculate
+		 * SNR. Just use raw level (units unknown). */
+		res->snr = res->level;
+	}
+}
+
+
+static unsigned int max_ht20_rate(int snr)
+{
+	if (snr < 6)
+		return 6500; /* HT20 MCS0 */
+	if (snr < 8)
+		return 13000; /* HT20 MCS1 */
+	if (snr < 13)
+		return 19500; /* HT20 MCS2 */
+	if (snr < 17)
+		return 26000; /* HT20 MCS3 */
+	if (snr < 20)
+		return 39000; /* HT20 MCS4 */
+	if (snr < 23)
+		return 52000; /* HT20 MCS5 */
+	if (snr < 24)
+		return 58500; /* HT20 MCS6 */
+	return 65000; /* HT20 MCS7 */
+}
+
+
+static unsigned int max_ht40_rate(int snr)
+{
+	if (snr < 3)
+		return 13500; /* HT40 MCS0 */
+	if (snr < 6)
+		return 27000; /* HT40 MCS1 */
+	if (snr < 10)
+		return 40500; /* HT40 MCS2 */
+	if (snr < 15)
+		return 54000; /* HT40 MCS3 */
+	if (snr < 17)
+		return 81000; /* HT40 MCS4 */
+	if (snr < 22)
+		return 108000; /* HT40 MCS5 */
+	if (snr < 24)
+		return 121500; /* HT40 MCS6 */
+	return 135000; /* HT40 MCS7 */
+}
+
+
+static unsigned int max_vht80_rate(int snr)
+{
+	if (snr < 1)
+		return 0;
+	if (snr < 2)
+		return 29300; /* VHT80 MCS0 */
+	if (snr < 5)
+		return 58500; /* VHT80 MCS1 */
+	if (snr < 9)
+		return 87800; /* VHT80 MCS2 */
+	if (snr < 11)
+		return 117000; /* VHT80 MCS3 */
+	if (snr < 15)
+		return 175500; /* VHT80 MCS4 */
+	if (snr < 16)
+		return 234000; /* VHT80 MCS5 */
+	if (snr < 18)
+		return 263300; /* VHT80 MCS6 */
+	if (snr < 20)
+		return 292500; /* VHT80 MCS7 */
+	if (snr < 22)
+		return 351000; /* VHT80 MCS8 */
+	return 390000; /* VHT80 MCS9 */
+}
+
+
+static void scan_est_throughput(struct wpa_supplicant *wpa_s,
+				struct wpa_scan_res *res)
+{
+	enum local_hw_capab capab = wpa_s->hw_capab;
+	int rate; /* max legacy rate in 500 kb/s units */
+	const u8 *ie;
+	unsigned int est, tmp;
+	int snr = res->snr;
+
+	if (res->est_throughput)
+		return;
+
+	/* Get maximum legacy rate */
+	rate = wpa_scan_get_max_rate(res);
+
+	/* Limit based on estimated SNR */
+	if (rate > 1 * 2 && snr < 1)
+		rate = 1 * 2;
+	else if (rate > 2 * 2 && snr < 4)
+		rate = 2 * 2;
+	else if (rate > 6 * 2 && snr < 5)
+		rate = 6 * 2;
+	else if (rate > 9 * 2 && snr < 6)
+		rate = 9 * 2;
+	else if (rate > 12 * 2 && snr < 7)
+		rate = 12 * 2;
+	else if (rate > 18 * 2 && snr < 10)
+		rate = 18 * 2;
+	else if (rate > 24 * 2 && snr < 11)
+		rate = 24 * 2;
+	else if (rate > 36 * 2 && snr < 15)
+		rate = 36 * 2;
+	else if (rate > 48 * 2 && snr < 19)
+		rate = 48 * 2;
+	else if (rate > 54 * 2 && snr < 21)
+		rate = 54 * 2;
+	est = rate * 500;
+
+	if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+		ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+		if (ie) {
+			tmp = max_ht20_rate(snr);
+			if (tmp > est)
+				est = tmp;
+		}
+	}
+
+	if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+		ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+		if (ie && ie[1] >= 2 &&
+		    (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+			tmp = max_ht40_rate(snr);
+			if (tmp > est)
+				est = tmp;
+		}
+	}
+
+	if (capab == CAPAB_VHT) {
+		/* Use +1 to assume VHT is always faster than HT */
+		ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+		if (ie) {
+			tmp = max_ht20_rate(snr) + 1;
+			if (tmp > est)
+				est = tmp;
+
+			ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+			if (ie && ie[1] >= 2 &&
+			    (ie[3] &
+			     HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+				tmp = max_ht40_rate(snr) + 1;
+				if (tmp > est)
+					est = tmp;
+			}
+
+			ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+			if (ie && ie[1] >= 1 &&
+			    (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
+				tmp = max_vht80_rate(snr) + 1;
+				if (tmp > est)
+					est = tmp;
+			}
+		}
+	}
+
+	/* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+
+	res->est_throughput = est;
+}
+
+
 /**
  * wpa_supplicant_get_scan_results - Get scan results
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1792,6 +2029,13 @@
 	}
 	filter_scan_res(wpa_s, scan_res);
 
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *scan_res_item = scan_res->res[i];
+
+		scan_snr(scan_res_item);
+		scan_est_throughput(wpa_s, scan_res_item);
+	}
+
 #ifdef CONFIG_WPS
 	if (wpas_wps_searching(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
@@ -1926,6 +2170,23 @@
 	params->only_new_results = src->only_new_results;
 	params->low_priority = src->low_priority;
 
+	if (src->mac_addr_rand) {
+		params->mac_addr_rand = src->mac_addr_rand;
+
+		if (src->mac_addr && src->mac_addr_mask) {
+			u8 *mac_addr;
+
+			mac_addr = os_malloc(2 * ETH_ALEN);
+			if (!mac_addr)
+				goto failed;
+
+			os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
+			os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
+				  ETH_ALEN);
+			params->mac_addr = mac_addr;
+			params->mac_addr_mask = mac_addr + ETH_ALEN;
+		}
+	}
 	return params;
 
 failed:
@@ -1946,13 +2207,20 @@
 	os_free((u8 *) params->extra_ies);
 	os_free(params->freqs);
 	os_free(params->filter_ssids);
+
+	/*
+	 * Note: params->mac_addr_mask points to same memory allocation and
+	 * must not be freed separately.
+	 */
+	os_free((u8 *) params->mac_addr);
+
 	os_free(params);
 }
 
 
 int wpas_start_pno(struct wpa_supplicant *wpa_s)
 {
-	int ret, interval;
+	int ret, interval, prio;
 	size_t i, num_ssid, num_match_ssid;
 	struct wpa_ssid *ssid;
 	struct wpa_driver_scan_params params;
@@ -2017,8 +2285,10 @@
 					sizeof(struct wpa_driver_scan_filter));
 	if (params.filter_ssids == NULL)
 		return -1;
+
 	i = 0;
-	ssid = wpa_s->conf->ssid;
+	prio = 0;
+	ssid = wpa_s->conf->pssid[prio];
 	while (ssid) {
 		if (!wpas_network_disabled(wpa_s, ssid)) {
 			if (ssid->scan_ssid && params.num_ssids < num_ssid) {
@@ -2036,7 +2306,12 @@
 			if (i == num_match_ssid)
 				break;
 		}
-		ssid = ssid->next;
+		if (ssid->pnext)
+			ssid = ssid->pnext;
+		else if (prio + 1 == wpa_s->conf->num_prio)
+			break;
+		else
+			ssid = wpa_s->conf->pssid[++prio];
 	}
 
 	if (wpa_s->conf->filter_rssi)
@@ -2050,6 +2325,14 @@
 		params.freqs = wpa_s->manual_sched_scan_freqs;
 	}
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_pno) {
+			params.mac_addr = wpa_s->mac_addr_pno;
+			params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
+		}
+	}
+
 	ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
 	os_free(params.filter_ssids);
 	if (ret == 0)
@@ -2077,3 +2360,61 @@
 
 	return ret;
 }
+
+
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+				    unsigned int type)
+{
+	type &= MAC_ADDR_RAND_ALL;
+	wpa_s->mac_addr_rand_enable &= ~type;
+
+	if (type & MAC_ADDR_RAND_SCAN) {
+		os_free(wpa_s->mac_addr_scan);
+		wpa_s->mac_addr_scan = NULL;
+	}
+
+	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+		os_free(wpa_s->mac_addr_sched_scan);
+		wpa_s->mac_addr_sched_scan = NULL;
+	}
+
+	if (type & MAC_ADDR_RAND_PNO) {
+		os_free(wpa_s->mac_addr_pno);
+		wpa_s->mac_addr_pno = NULL;
+	}
+}
+
+
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+				unsigned int type, const u8 *addr,
+				const u8 *mask)
+{
+	u8 *tmp = NULL;
+
+	wpas_mac_addr_rand_scan_clear(wpa_s, type);
+
+	if (addr) {
+		tmp = os_malloc(2 * ETH_ALEN);
+		if (!tmp)
+			return -1;
+		os_memcpy(tmp, addr, ETH_ALEN);
+		os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
+	}
+
+	if (type == MAC_ADDR_RAND_SCAN) {
+		wpa_s->mac_addr_scan = tmp;
+	} else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+		wpa_s->mac_addr_sched_scan = tmp;
+	} else if (type == MAC_ADDR_RAND_PNO) {
+		wpa_s->mac_addr_pno = tmp;
+	} else {
+		wpa_printf(MSG_INFO,
+			   "scan: Invalid MAC randomization type=0x%x",
+			   type);
+		os_free(tmp);
+		return -1;
+	}
+
+	wpa_s->mac_addr_rand_enable |= type;
+	return 0;
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 946d2b3..7650f5a 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -49,4 +49,10 @@
 int wpas_start_pno(struct wpa_supplicant *wpa_s);
 int wpas_stop_pno(struct wpa_supplicant *wpa_s);
 
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+				   unsigned int type);
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+				unsigned int type, const u8 *addr,
+				const u8 *mask);
+
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 80c280a..1788113 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -207,6 +207,7 @@
 	struct wpabuf *resp = NULL;
 	u8 ext_capab[18];
 	int ext_capab_len;
+	int skip_auth;
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -215,6 +216,8 @@
 		return;
 	}
 
+	skip_auth = wpa_s->conf->reassoc_same_bss_optim &&
+		wpa_s->reassoc_same_bss;
 	wpa_s->current_bss = bss;
 
 	os_memset(&params, 0, sizeof(params));
@@ -297,7 +300,7 @@
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    wpa_s->current_ssid,
 					    try_opportunistic) == 0)
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
 					      wpa_s->sme.assoc_req_ie,
@@ -384,8 +387,7 @@
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-	wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-		wpa_s->conf->pmf : ssid->ieee80211w;
+	wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
 	if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
 		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 		struct wpa_ie_data _ie;
@@ -449,10 +451,24 @@
 		os_memcpy(pos, ext_capab, ext_capab_len);
 	}
 
+	if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+		struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+		size_t len;
+
+		len = sizeof(wpa_s->sme.assoc_req_ie) -
+			wpa_s->sme.assoc_req_ie_len;
+		if (wpabuf_len(buf) <= len) {
+			os_memcpy(wpa_s->sme.assoc_req_ie +
+				  wpa_s->sme.assoc_req_ie_len,
+				  wpabuf_head(buf), wpabuf_len(buf));
+			wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
+		}
+	}
+
 	sme_auth_handle_rrm(wpa_s, bss);
 
 #ifdef CONFIG_SAE
-	if (params.auth_alg == WPA_AUTH_ALG_SAE &&
+	if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
 	    pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
 	{
 		wpa_dbg(wpa_s, MSG_DEBUG,
@@ -461,7 +477,7 @@
 		wpa_s->sme.sae_pmksa_caching = 1;
 	}
 
-	if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+	if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
 		if (start)
 			resp = sme_auth_build_sae_commit(wpa_s, ssid,
 							 bss->bssid);
@@ -519,6 +535,15 @@
 	}
 #endif /* CONFIG_P2P */
 
+	if (skip_auth) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"SME: Skip authentication step on reassoc-to-same-BSS");
+		wpabuf_free(resp);
+		sme_associate(wpa_s, ssid->mode, bss->bssid, WLAN_AUTH_OPEN);
+		return;
+	}
+
+
 	wpa_s->sme.auth_alg = params.auth_alg;
 	if (wpa_drv_authenticate(wpa_s, &params) < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
@@ -1533,9 +1558,7 @@
 	if (wpa_s->wpa_state != WPA_COMPLETED)
 		return;
 	ssid = wpa_s->current_ssid;
-	if (ssid == NULL ||
-	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
+	if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
 		return;
 	if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
 		return;
diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c
index 727df41..5625d36 100644
--- a/wpa_supplicant/wmm_ac.c
+++ b/wpa_supplicant/wmm_ac.c
@@ -427,7 +427,7 @@
 	int i;
 
 	/* Parsing WMM Parameter Element */
-	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) != ParseOK) {
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
 		wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies");
 		return NULL;
 	}
@@ -857,7 +857,7 @@
 	struct wmm_ac_assoc_data *assoc_info = wpa_s->wmm_ac_assoc_info;
 	enum ts_dir_idx idx;
 	int pos = 0;
-	u8 ac;
+	u8 ac, up;
 
 	if (!assoc_info) {
 		return wpa_scnprintf(buf, buflen - pos,
@@ -889,13 +889,14 @@
 			dir = wmm_ac_get_direction(tspec);
 			dir_str = get_direction_str(dir);
 			tsid = wmm_ac_get_tsid(tspec);
+			up = wmm_ac_get_user_priority(tspec);
 
 			pos += wpa_scnprintf(buf + pos, buflen - pos,
-					     "\tTSID = %u\n"
+					     "\tTSID=%u UP=%u\n"
 					     "\tAddress = "MACSTR"\n"
 					     "\tWMM AC dir = %s\n"
 					     "\tTotal admitted time = %u\n\n",
-					     tsid,
+					     tsid, up,
 					     MAC2STR(wpa_s->bssid),
 					     dir_str,
 					     le_to_host16(tspec->medium_time));
@@ -909,3 +910,86 @@
 
 	return pos;
 }
+
+
+static u8 wmm_ac_get_tspecs_count(struct wpa_supplicant *wpa_s)
+{
+	int ac, dir, tspecs_count = 0;
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+			if (wpa_s->tspecs[ac][dir])
+				tspecs_count++;
+		}
+	}
+
+	return tspecs_count;
+}
+
+
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s)
+{
+	int ac, dir, tspecs_count;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Save last configured tspecs");
+
+	if (!wpa_s->wmm_ac_assoc_info)
+		return;
+
+	tspecs_count = wmm_ac_get_tspecs_count(wpa_s);
+	if (!tspecs_count) {
+		wpa_printf(MSG_DEBUG, "WMM AC: No configured TSPECs");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Saving tspecs");
+
+	wmm_ac_clear_saved_tspecs(wpa_s);
+	wpa_s->last_tspecs = os_calloc(tspecs_count,
+				       sizeof(*wpa_s->last_tspecs));
+	if (!wpa_s->last_tspecs) {
+		wpa_printf(MSG_ERROR, "WMM AC: Failed to save tspecs!");
+		return;
+	}
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+			if (!wpa_s->tspecs[ac][dir])
+				continue;
+
+			wpa_s->last_tspecs[wpa_s->last_tspecs_count++] =
+				*wpa_s->tspecs[ac][dir];
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Successfully saved %d TSPECs",
+		   wpa_s->last_tspecs_count);
+}
+
+
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->last_tspecs) {
+		wpa_printf(MSG_DEBUG, "WMM AC: Clear saved tspecs");
+		os_free(wpa_s->last_tspecs);
+		wpa_s->last_tspecs = NULL;
+		wpa_s->last_tspecs_count = 0;
+	}
+}
+
+
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+
+	if (!wpa_s->wmm_ac_assoc_info || !wpa_s->last_tspecs_count)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Restore %u saved tspecs",
+		   wpa_s->last_tspecs_count);
+
+	for (i = 0; i < wpa_s->last_tspecs_count; i++)
+		wmm_ac_add_ts(wpa_s, wpa_s->bssid, &wpa_s->last_tspecs[i]);
+
+	return 0;
+}
diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h
index 2b02025..5171b16 100644
--- a/wpa_supplicant/wmm_ac.h
+++ b/wpa_supplicant/wmm_ac.h
@@ -169,5 +169,8 @@
 void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
 			const u8 *sa, const u8 *data, size_t len);
 int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen);
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s);
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s);
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s);
 
 #endif /* WMM_AC_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 87071fa..9fbc532 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -28,7 +28,7 @@
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -92,6 +92,7 @@
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
 
 
 static void print_help(const char *cmd);
@@ -99,6 +100,7 @@
 static void wpa_cli_close_connection(void);
 static char * wpa_cli_get_default_ifname(void);
 static char ** wpa_list_cmd_list(void);
+static void update_networks(struct wpa_ctrl *ctrl);
 
 
 static void usage(void)
@@ -168,11 +170,12 @@
 
 
 #ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
+static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+				  int separator)
 {
 	const char *end;
 	char *buf;
-	end = os_strchr(txt, ' ');
+	end = os_strchr(txt, separator);
 	if (end == NULL)
 		end = txt + os_strlen(txt);
 	buf = dup_binstr(txt, end - txt);
@@ -213,14 +216,16 @@
 	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
 	return cli_txt_list_add(txt_list, buf);
 }
+#endif /* CONFIG_P2P */
 
 
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
+static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+				 int separator)
 {
 	const char *end;
 	char *buf;
 	int ret;
-	end = os_strchr(txt, ' ');
+	end = os_strchr(txt, separator);
 	if (end == NULL)
 		end = txt + os_strlen(txt);
 	buf = dup_binstr(txt, end - txt);
@@ -230,7 +235,6 @@
 	os_free(buf);
 	return ret;
 }
-#endif /* CONFIG_P2P */
 
 
 static char ** cli_txt_list_array(struct dl_list *txt_list)
@@ -608,35 +612,57 @@
 		"uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
 		"no_keep_alive",
 		/* global configuration parameters */
-		"eapol_version", "ap_scan", "disable_scan_offload",
-		"fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
-		"pkcs11_module_path", "openssl_ciphers",
-		"pcsc_reader", "pcsc_pin",
-		"driver_param", "dot11RSNAConfigPMKLifetime",
+#ifdef CONFIG_CTRL_IFACE
+		"ctrl_interface", "no_ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+		"eapol_version", "ap_scan", "bgscan",
+#ifdef CONFIG_MESH
+		"user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+		"disable_scan_offload", "fast_reauth", "opensc_engine_path",
+		"pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+		"pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+		"dot11RSNAConfigPMKLifetime",
 		"dot11RSNAConfigPMKReauthThreshold",
 		"dot11RSNAConfigSATimeout",
-		"update_config", "load_dynamic_eap", "uuid", "device_name",
-		"manufacturer", "model_name", "model_number", "serial_number",
-		"device_type", "os_version", "config_methods",
-		"wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+#ifndef CONFIG_NO_CONFIG_WRITE
+		"update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+		"load_dynamic_eap",
+#ifdef CONFIG_WPS
+		"uuid", "device_name", "manufacturer", "model_name",
+		"model_number", "serial_number", "device_type", "os_version",
+		"config_methods", "wps_cred_processing", "wps_vendor_ext_m1",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+		"sec_device_type",
 		"p2p_listen_reg_class", "p2p_listen_channel",
-		"p2p_oper_reg_class", "p2p_oper_channel",
-		"p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
-		"p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
-		"p2p_no_go_freq",
-		"p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
-		"p2p_go_vht",
-		"p2p_ignore_shared_freq", "country", "bss_max_count",
-		"bss_expiration_age", "bss_expiration_scan_count",
-		"filter_ssids", "filter_rssi", "max_num_sta",
-		"disassoc_low_ack", "hs20", "interworking", "hessid",
-		"access_network_type", "pbc_in_m1", "autoscan",
-		"wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
-		"wps_nfc_dev_pw", "ext_password_backend",
+		"p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+		"p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+		"p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan",
+		"p2p_no_go_freq", "p2p_add_cli_chan",
+		"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+		"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+		"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+		"ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+		"country", "bss_max_count", "bss_expiration_age",
+		"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+		"max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+		"hs20",
+#endif /* CONFIG_HS20 */
+		"interworking", "hessid", "access_network_type", "pbc_in_m1",
+		"autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
+		"wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
 		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
-		"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
-		"ignore_old_scan_res", "freq_list", "external_sim",
-		"tdls_external_control", "p2p_search_delay"
+		"sae_groups", "dtim_period", "beacon_int",
+		"ap_vendor_elements", "ignore_old_scan_res", "freq_list",
+		"scan_cur_freq", "sched_scan_interval",
+		"tdls_external_control", "osu_dir", "wowlan_triggers",
+		"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+		"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+		"reassoc_same_bss_optim"
 	};
 	int i, num_fields = ARRAY_SIZE(fields);
 
@@ -658,6 +684,11 @@
 	return NULL;
 }
 
+static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DUMP");
+}
+
 
 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -665,6 +696,74 @@
 }
 
 
+static char ** wpa_cli_complete_get(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	const char *fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+		"ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+		"eapol_version", "ap_scan",
+#ifdef CONFIG_MESH
+		"user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+		"disable_scan_offload", "fast_reauth", "opensc_engine_path",
+		"pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+		"pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+		"dot11RSNAConfigPMKLifetime",
+		"dot11RSNAConfigPMKReauthThreshold",
+		"dot11RSNAConfigSATimeout",
+#ifndef CONFIG_NO_CONFIG_WRITE
+		"update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+#ifdef CONFIG_WPS
+		"device_name", "manufacturer", "model_name", "model_number",
+		"serial_number", "config_methods", "wps_cred_processing",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+		"p2p_listen_reg_class", "p2p_listen_channel",
+		"p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+		"p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+		"p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan",
+		"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+		"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+		"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+		"ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+		"bss_max_count", "bss_expiration_age",
+		"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+		"max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+		"hs20",
+#endif /* CONFIG_HS20 */
+		"interworking", "access_network_type", "pbc_in_m1", "autoscan",
+		"wps_nfc_dev_pw_id", "ext_password_backend",
+		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+		"dtim_period", "beacon_int", "ignore_old_scan_res",
+		"scan_cur_freq", "sched_scan_interval",
+		"tdls_external_control", "osu_dir", "wowlan_triggers",
+		"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+		"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+		"reassoc_same_bss_optim"
+	};
+	int i, num_fields = ARRAY_SIZE(fields);
+
+	if (arg == 1) {
+		char **res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(fields[i]);
+			if (res[i] == NULL)
+				return res;
+		}
+		return res;
+	}
+
+	return NULL;
+}
+
+
 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	return wpa_ctrl_command(ctrl, "LOGOFF");
@@ -868,12 +967,12 @@
 		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
 				  argv[0], argv[1]);
 	else if (argc == 5 || argc == 6) {
-		char ssid_hex[2 * 32 + 1];
+		char ssid_hex[2 * SSID_MAX_LEN + 1];
 		char key_hex[2 * 64 + 1];
 		int i;
 
 		ssid_hex[0] = '\0';
-		for (i = 0; i < 32; i++) {
+		for (i = 0; i < SSID_MAX_LEN; i++) {
 			if (argv[2][i] == '\0')
 				break;
 			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
@@ -997,12 +1096,12 @@
 	int res;
 
 	if (argc == 5 || argc == 6) {
-		char ssid_hex[2 * 32 + 1];
+		char ssid_hex[2 * SSID_MAX_LEN + 1];
 		char key_hex[2 * 64 + 1];
 		int i;
 
 		ssid_hex[0] = '\0';
-		for (i = 0; i < 32; i++) {
+		for (i = 0; i < SSID_MAX_LEN; i++) {
 			if (argv[2][i] == '\0')
 				break;
 			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
@@ -1356,14 +1455,18 @@
 static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
-	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
+	int res = wpa_ctrl_command(ctrl, "ADD_NETWORK");
+	update_networks(ctrl);
+	return res;
 }
 
 
 static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
 				      char *argv[])
 {
-	return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
+	int res = wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
+	update_networks(ctrl);
+	return res;
 }
 
 
@@ -1424,6 +1527,105 @@
 }
 
 
+static const char *network_fields[] = {
+	"ssid", "scan_ssid", "bssid", "bssid_blacklist",
+	"bssid_whitelist", "psk", "proto", "key_mgmt",
+	"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
+	"freq_list",
+#ifdef IEEE8021X_EAPOL
+	"eap", "identity", "anonymous_identity", "password", "ca_cert",
+	"ca_path", "client_cert", "private_key", "private_key_passwd",
+	"dh_file", "subject_match", "altsubject_match",
+	"domain_suffix_match", "domain_match", "ca_cert2", "ca_path2",
+	"client_cert2", "private_key2", "private_key2_passwd",
+	"dh_file2", "subject_match2", "altsubject_match2",
+	"domain_suffix_match2", "domain_match2", "phase1", "phase2",
+	"pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id",
+	"pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id",
+	"engine", "engine2", "eapol_flags", "sim_num",
+	"openssl_ciphers", "erp",
+#endif /* IEEE8021X_EAPOL */
+	"wep_key0", "wep_key1", "wep_key2", "wep_key3",
+	"wep_tx_keyidx", "priority",
+#ifdef IEEE8021X_EAPOL
+	"eap_workaround", "pac_file", "fragment_size", "ocsp",
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+	"mode", "no_auto_peer",
+#else /* CONFIG_MESH */
+	"mode",
+#endif /* CONFIG_MESH */
+	"proactive_key_caching", "disabled", "id_str",
+#ifdef CONFIG_IEEE80211W
+	"ieee80211w",
+#endif /* CONFIG_IEEE80211W */
+	"peerkey", "mixed_cell", "frequency", "fixed_freq",
+#ifdef CONFIG_MESH
+	"mesh_basic_rates", "dot11MeshMaxRetries",
+	"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
+	"dot11MeshHoldingTimeout",
+#endif /* CONFIG_MESH */
+	"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+#ifdef CONFIG_P2P
+	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+	"disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc",
+	"ht40_intolerant", "disable_max_amsdu", "ampdu_factor",
+	"ampdu_density", "ht_mcs",
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+	"disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1",
+	"vht_rx_mcs_nss_2", "vht_rx_mcs_nss_3", "vht_rx_mcs_nss_4",
+	"vht_rx_mcs_nss_5", "vht_rx_mcs_nss_6", "vht_rx_mcs_nss_7",
+	"vht_rx_mcs_nss_8", "vht_tx_mcs_nss_1", "vht_tx_mcs_nss_2",
+	"vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
+	"vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
+#endif /* CONFIG_VHT_OVERRIDES */
+	"ap_max_inactivity", "dtim_period", "beacon_int",
+#ifdef CONFIG_MACSEC
+	"macsec_policy",
+#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_HS20
+	"update_identifier",
+#endif /* CONFIG_HS20 */
+	"mac_addr"
+};
+
+
+static char ** wpa_cli_complete_network(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	int i, num_fields = ARRAY_SIZE(network_fields);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&networks);
+		break;
+	case 2:
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(network_fields[i]);
+			if (res[i] == NULL)
+				break;
+		}
+	}
+	return res;
+}
+
+
+static char ** wpa_cli_complete_network_id(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	if (arg == 1)
+		return cli_txt_list_array(&networks);
+	return NULL;
+}
+
+
 static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
@@ -1442,6 +1644,31 @@
 }
 
 
+static char ** wpa_cli_complete_dup_network(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	int i, num_fields = ARRAY_SIZE(network_fields);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+	case 2:
+		res = cli_txt_list_array(&networks);
+		break;
+	case 3:
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(network_fields[i]);
+			if (res[i] == NULL)
+				break;
+		}
+	}
+	return res;
+}
+
+
 static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
 				  char *argv[])
 {
@@ -1577,6 +1804,10 @@
 	wpa_cli_close_connection();
 	os_free(ctrl_ifname);
 	ctrl_ifname = os_strdup(argv[0]);
+	if (!ctrl_ifname) {
+		printf("Failed to allocate memory\n");
+		return 0;
+	}
 
 	if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
 		printf("Connected to interface '%s.\n", ctrl_ifname);
@@ -1612,20 +1843,20 @@
 		printf("Invalid INTERFACE_ADD command: needs at least one "
 		       "argument (interface name)\n"
 		       "All arguments: ifname confname driver ctrl_interface "
-		       "driver_param bridge_name\n");
+		       "driver_param bridge_name [create]\n");
 		return -1;
 	}
 
 	/*
 	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
-	 * <driver_param>TAB<bridge_name>
+	 * <driver_param>TAB<bridge_name>[TAB<create>]
 	 */
 	res = os_snprintf(cmd, sizeof(cmd),
-			  "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+			  "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
 			  argv[0],
 			  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
 			  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
-			  argc > 5 ? argv[5] : "");
+			  argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
 	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
@@ -1821,6 +2052,20 @@
 }
 
 
+static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
+					      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
+}
+
+
 static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
@@ -1905,11 +2150,9 @@
 {
 	char cmd[4096];
 
-	if (argc != 2 && argc != 4) {
+	if (argc < 2) {
 		printf("Invalid P2P_SERV_DISC_REQ command: needs two "
-		       "arguments (address and TLVs) or four arguments "
-		       "(address, \"upnp\", version, search target "
-		       "(SSDP ST:)\n");
+		       "or more arguments (address and TLVs)\n");
 		return -1;
 	}
 
@@ -1971,27 +2214,25 @@
 static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
 				       char *argv[])
 {
-	char cmd[4096];
-	int res;
+	if (argc < 3) {
+		printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
+		return -1;
+	}
 
-	if (argc != 3 && argc != 4) {
-		printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+	return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	if (argc < 5 || argc > 6) {
+		printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
 		       "arguments\n");
 		return -1;
 	}
 
-	if (argc == 4)
-		res = os_snprintf(cmd, sizeof(cmd),
-				  "P2P_SERVICE_ADD %s %s %s %s",
-				  argv[0], argv[1], argv[2], argv[3]);
-	else
-		res = os_snprintf(cmd, sizeof(cmd),
-				  "P2P_SERVICE_ADD %s %s %s",
-				  argv[0], argv[1], argv[2]);
-	if (os_snprintf_error(sizeof(cmd), res))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-	return wpa_ctrl_command(ctrl, cmd);
+	return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
 }
 
 
@@ -2295,6 +2536,13 @@
 }
 
 
+static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
+						char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
+}
+
+
 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);
@@ -2426,6 +2674,20 @@
 }
 
 
+static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
+					       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
@@ -2523,6 +2785,13 @@
 }
 
 
+static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
+}
+
+
 enum wpa_cli_cmd_flags {
 	cli_cmd_flag_none		= 0x00,
 	cli_cmd_flag_sensitive		= 0x01
@@ -2574,7 +2843,10 @@
 	  cli_cmd_flag_none,
 	  "= set variables (shows list of variables when run without "
 	  "arguments)" },
-	{ "get", wpa_cli_cmd_get, NULL,
+	{ "dump", wpa_cli_cmd_dump, NULL,
+	  cli_cmd_flag_none,
+	  "= dump config variables" },
+	{ "get", wpa_cli_cmd_get, wpa_cli_complete_get,
 	  cli_cmd_flag_none,
 	  "<name> = get information" },
 	{ "logon", wpa_cli_cmd_logon, NULL,
@@ -2636,29 +2908,33 @@
 	{ "list_networks", wpa_cli_cmd_list_networks, NULL,
 	  cli_cmd_flag_none,
 	  "= list configured networks" },
-	{ "select_network", wpa_cli_cmd_select_network, NULL,
+	{ "select_network", wpa_cli_cmd_select_network,
+	  wpa_cli_complete_network_id,
 	  cli_cmd_flag_none,
 	  "<network id> = select a network (disable others)" },
-	{ "enable_network", wpa_cli_cmd_enable_network, NULL,
+	{ "enable_network", wpa_cli_cmd_enable_network,
+	  wpa_cli_complete_network_id,
 	  cli_cmd_flag_none,
 	  "<network id> = enable a network" },
-	{ "disable_network", wpa_cli_cmd_disable_network, NULL,
+	{ "disable_network", wpa_cli_cmd_disable_network,
+	  wpa_cli_complete_network_id,
 	  cli_cmd_flag_none,
 	  "<network id> = disable a network" },
 	{ "add_network", wpa_cli_cmd_add_network, NULL,
 	  cli_cmd_flag_none,
 	  "= add a network" },
-	{ "remove_network", wpa_cli_cmd_remove_network, NULL,
+	{ "remove_network", wpa_cli_cmd_remove_network,
+	  wpa_cli_complete_network_id,
 	  cli_cmd_flag_none,
 	  "<network id> = remove a network" },
-	{ "set_network", wpa_cli_cmd_set_network, NULL,
+	{ "set_network", wpa_cli_cmd_set_network, wpa_cli_complete_network,
 	  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, NULL,
+	{ "get_network", wpa_cli_cmd_get_network, wpa_cli_complete_network,
 	  cli_cmd_flag_none,
 	  "<network id> <variable> = get network variables" },
-	{ "dup_network", wpa_cli_cmd_dup_network, NULL,
+	{ "dup_network", wpa_cli_cmd_dup_network, wpa_cli_complete_dup_network,
 	  cli_cmd_flag_none,
 	  "<src network id> <dst network id> <variable> = duplicate network variables"
 	},
@@ -2700,7 +2976,7 @@
 	{ "get_capability", wpa_cli_cmd_get_capability, NULL,
 	  cli_cmd_flag_none,
 	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
-	  "= get capabilies" },
+	  "= get capabilities" },
 	{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
 	  cli_cmd_flag_none,
 	  "= force wpa_supplicant to re-read its configuration file" },
@@ -2857,6 +3133,12 @@
 	  "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
 	{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
 	  "= stop P2P Devices search" },
+	{ "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
+	{ "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
 	{ "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" },
@@ -2893,8 +3175,12 @@
 	  "= remove all stored service entries" },
 	{ "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
 	  cli_cmd_flag_none,
-	  "<bonjour|upnp> <query|version> <response|service> = add a local "
+	  "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
 	  "service" },
+	{ "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
+	  cli_cmd_flag_none,
+	  "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
+	  "local ASP service" },
 	{ "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
 	  cli_cmd_flag_none,
 	  "<bonjour|upnp> <query|version> [|service] = remove a local "
@@ -2952,6 +3238,9 @@
 	{ "interworking_connect", wpa_cli_cmd_interworking_connect,
 	  wpa_cli_complete_bss, cli_cmd_flag_none,
 	  "<BSSID> = connect using Interworking credentials" },
+	{ "interworking_add_network", wpa_cli_cmd_interworking_add_network,
+	  wpa_cli_complete_bss, cli_cmd_flag_none,
+	  "<BSSID> = connect using Interworking credentials" },
 	{ "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
 	  cli_cmd_flag_none,
 	  "<addr> <info id>[,<info id>]... = request ANQP information" },
@@ -3002,6 +3291,14 @@
 	{ "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
 	  cli_cmd_flag_none,
 	  "= show status for Wireless Multi-Media Admission-Control" },
+	{ "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
+	  "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
+	  "with TDLS peer" },
+	{ "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = disable channel switching with TDLS peer <addr>" },
 	{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
 	  cli_cmd_flag_none,
 	  "= get signal parameters" },
@@ -3041,6 +3338,11 @@
 	},
 	{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
 	  "= flush ERP keys" },
+	{ "mac_rand_scan",
+	  wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
+	  "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
+	  "mask=mac-address-mask] = scan MAC randomization"
+	},
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -3448,7 +3750,7 @@
 		s = os_strchr(start, ' ');
 		if (s == NULL)
 			return;
-		cli_txt_list_add_word(&p2p_groups, s + 1);
+		cli_txt_list_add_word(&p2p_groups, s + 1, ' ');
 		return;
 	}
 
@@ -3456,7 +3758,7 @@
 		s = os_strchr(start, ' ');
 		if (s == NULL)
 			return;
-		cli_txt_list_del_word(&p2p_groups, s + 1);
+		cli_txt_list_del_word(&p2p_groups, s + 1, ' ');
 		return;
 	}
 #endif /* CONFIG_P2P */
@@ -3615,7 +3917,11 @@
 	ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
+#ifdef CONFIG_WPA_CLI_HISTORY_DIR
+	home = CONFIG_WPA_CLI_HISTORY_DIR;
+#else /* CONFIG_WPA_CLI_HISTORY_DIR */
 	home = getenv("HOME");
+#endif /* CONFIG_WPA_CLI_HISTORY_DIR */
 	if (home) {
 		const char *fname = ".wpa_cli_history";
 		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
@@ -3698,6 +4004,38 @@
 }
 
 
+static void update_networks(struct wpa_ctrl *ctrl)
+{
+	char buf[4096];
+	size_t len = sizeof(buf);
+	int ret;
+	char *cmd = "LIST_NETWORKS";
+	char *pos, *end;
+	int header = 1;
+
+	cli_txt_list_flush(&networks);
+
+	if (ctrl == NULL)
+		return;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+	if (ret < 0)
+		return;
+	buf[len] = '\0';
+
+	pos = buf;
+	while (pos) {
+		end = os_strchr(pos, '\n');
+		if (end == NULL)
+			break;
+		*end = '\0';
+		if (!header)
+			cli_txt_list_add_word(&networks, pos, '\t');
+		header = 0;
+		pos = end + 1;
+	}
+}
+
+
 static void try_connection(void *eloop_ctx, void *timeout_ctx)
 {
 	if (ctrl_conn)
@@ -3709,7 +4047,8 @@
 	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);
+			       "%s - re-trying\n",
+			       ctrl_ifname ? ctrl_ifname : "(nil)");
 			warning_displayed = 1;
 		}
 		eloop_register_timeout(1, 0, try_connection, NULL, NULL);
@@ -3717,6 +4056,7 @@
 	}
 
 	update_bssid_list(ctrl_conn);
+	update_networks(ctrl_conn);
 
 	if (warning_displayed)
 		printf("Connection established.\n");
@@ -3738,6 +4078,7 @@
 	cli_txt_list_flush(&p2p_groups);
 	cli_txt_list_flush(&bsses);
 	cli_txt_list_flush(&ifnames);
+	cli_txt_list_flush(&networks);
 	if (edit_started)
 		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
 	os_free(hfile);
@@ -3970,7 +4311,8 @@
 		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
 			fprintf(stderr, "Failed to connect to non-global "
 				"ctrl_ifname: %s  error: %s\n",
-				ctrl_ifname, strerror(errno));
+				ctrl_ifname ? ctrl_ifname : "(nil)",
+				strerror(errno));
 			return -1;
 		}
 
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
index 063347e..ae0c240 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -12,6 +12,7 @@
 #include "signalbar.h"
 #include "wpagui.h"
 #include "networkconfig.h"
+#include "scanresultsitem.h"
 
 
 ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
@@ -95,7 +96,7 @@
 				ssid = (*it).mid(pos);
 		}
 
-		QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget);
+		ScanResultsItem *item = new ScanResultsItem(scanResultsWidget);
 		if (item) {
 			item->setText(0, ssid);
 			item->setText(1, bssid);
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp
new file mode 100644
index 0000000..9cd937c
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp
@@ -0,0 +1,18 @@
+/*
+ * wpa_gui - ScanResultsItem class
+ * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "scanresultsitem.h"
+
+bool ScanResultsItem::operator< (const QTreeWidgetItem &other) const
+{
+	int sortCol = treeWidget()->sortColumn();
+	if (sortCol == 2 || sortCol == 3) {
+		return text(sortCol).toInt() < other.text(sortCol).toInt();
+	}
+	return text(sortCol) < other.text(sortCol);
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h
new file mode 100644
index 0000000..835b7c0
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h
@@ -0,0 +1,21 @@
+/*
+ * wpa_gui - ScanResultsItem class
+ * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SCANRESULTSITEM_H
+#define SCANRESULTSITEM_H
+
+#include <QtGui>
+
+class ScanResultsItem : public QTreeWidgetItem
+{
+public:
+	ScanResultsItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
+	bool operator< (const QTreeWidgetItem &other) const;
+};
+
+#endif /* SCANRESULTSITEM_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
index 3c81929..69bc0f6 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -34,6 +34,7 @@
 	wpagui.h \
 	eventhistory.h \
 	scanresults.h \
+	scanresultsitem.h \
 	signalbar.h \
 	userdatarequest.h \
 	networkconfig.h \
@@ -45,6 +46,7 @@
 	wpagui.cpp \
 	eventhistory.cpp \
 	scanresults.cpp \
+	scanresultsitem.cpp \
 	signalbar.cpp \
 	userdatarequest.cpp \
 	networkconfig.cpp \
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 6276176..408e387 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -23,15 +23,14 @@
 #include "userdatarequest.h"
 #include "networkconfig.h"
 
-#if 1
-/* Silence stdout */
-#define printf wpagui_printf
-static int wpagui_printf(const char *, ...)
-{
-	return 0;
-}
+
+#ifndef QT_NO_DEBUG
+#define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__)
+#else
+#define debug(M, ...) do {} while (0)
 #endif
 
+
 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags)
 	: QMainWindow(parent), app(_app)
 {
@@ -136,6 +135,7 @@
 	monitor_conn = NULL;
 	msgNotifier = NULL;
 	ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
+	signalMeterInterval = 0;
 
 	parse_argv();
 
@@ -162,9 +162,13 @@
 	timer->setSingleShot(FALSE);
 	timer->start(1000);
 
+	signalMeterTimer = new QTimer(this);
+	signalMeterTimer->setInterval(signalMeterInterval);
+	connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate()));
+
 	if (openCtrlConnection(ctrl_iface) < 0) {
-		printf("Failed to open control connection to "
-		       "wpa_supplicant.\n");
+		debug("Failed to open control connection to "
+		      "wpa_supplicant.");
 	}
 
 	updateStatus();
@@ -235,7 +239,7 @@
 {
 	int c;
 	for (;;) {
-		c = getopt(qApp->argc(), qApp->argv(), "i:p:tq");
+		c = getopt(qApp->argc(), qApp->argv(), "i:m:p:tq");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -243,6 +247,9 @@
 			free(ctrl_iface);
 			ctrl_iface = strdup(optarg);
 			break;
+		case 'm':
+			signalMeterInterval = atoi(optarg) * 1000;
+			break;
 		case 'p':
 			free(ctrl_iface_dir);
 			ctrl_iface_dir = strdup(optarg);
@@ -295,8 +302,8 @@
 				if (strcmp(dent->d_name, ".") == 0 ||
 				    strcmp(dent->d_name, "..") == 0)
 					continue;
-				printf("Selected interface '%s'\n",
-				       dent->d_name);
+				debug("Selected interface '%s'",
+				      dent->d_name);
 				ctrl_iface = strdup(dent->d_name);
 				break;
 			}
@@ -373,7 +380,7 @@
 		monitor_conn = NULL;
 	}
 
-	printf("Trying to connect to '%s'\n", cfile);
+	debug("Trying to connect to '%s'", cfile);
 	ctrl_conn = wpa_ctrl_open(cfile);
 	if (ctrl_conn == NULL) {
 		free(cfile);
@@ -386,7 +393,7 @@
 		return -1;
 	}
 	if (wpa_ctrl_attach(monitor_conn)) {
-		printf("Failed to attach to wpa_supplicant\n");
+		debug("Failed to attach to wpa_supplicant");
 		wpa_ctrl_close(monitor_conn);
 		monitor_conn = NULL;
 		wpa_ctrl_close(ctrl_conn);
@@ -447,9 +454,9 @@
 		return -3;
 	ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
 	if (ret == -2)
-		printf("'%s' command timed out.\n", cmd);
+		debug("'%s' command timed out.", cmd);
 	else if (ret < 0)
-		printf("'%s' command failed.\n", cmd);
+		debug("'%s' command failed.", cmd);
 
 	return ret;
 }
@@ -497,6 +504,8 @@
 		textBssid->clear();
 		textIpAddress->clear();
 		updateTrayToolTip(tr("no status information"));
+		updateTrayIcon(TrayIconOffline);
+		signalMeterTimer->stop();
 
 #ifdef CONFIG_NATIVE_WINDOWS
 		static bool first = true;
@@ -545,6 +554,11 @@
 				ssid_updated = true;
 				textSsid->setText(pos);
 				updateTrayToolTip(pos + tr(" (associated)"));
+				if (!signalMeterInterval) {
+					/* if signal meter is not enabled show
+					 * full signal strength */
+					updateTrayIcon(TrayIconSignalExcellent);
+				}
 			} else if (strcmp(start, "ip_address") == 0) {
 				ipaddr_updated = true;
 				textIpAddress->setText(pos);
@@ -588,6 +602,23 @@
 	} else
 		textEncryption->clear();
 
+	if (signalMeterInterval) {
+		/*
+		 * Handle signal meter service. When network is not associated,
+		 * deactivate timer, otherwise keep it going. Tray icon has to
+		 * be initialized here, because of the initial delay of the
+		 * timer.
+		 */
+		if (ssid_updated) {
+			if (!signalMeterTimer->isActive()) {
+				updateTrayIcon(TrayIconConnected);
+				signalMeterTimer->start();
+			}
+		} else {
+			signalMeterTimer->stop();
+		}
+	}
+
 	if (!status_updated)
 		textStatus->clear();
 	if (!auth_updated)
@@ -595,6 +626,7 @@
 	if (!ssid_updated) {
 		textSsid->clear();
 		updateTrayToolTip(tr("(not-associated)"));
+		updateTrayIcon(TrayIconOffline);
 	}
 	if (!bssid_updated)
 		textBssid->clear();
@@ -705,13 +737,13 @@
 
 void WpaGui::helpIndex()
 {
-	printf("helpIndex\n");
+	debug("helpIndex");
 }
 
 
 void WpaGui::helpContents()
 {
-	printf("helpContents\n");
+	debug("helpContents");
 }
 
 
@@ -806,9 +838,9 @@
 
 	len = sizeof(buf) - 1;
 	if (ctrlRequest("PING", buf, &len) < 0) {
-		printf("PING failed - trying to reconnect\n");
+		debug("PING failed - trying to reconnect");
 		if (openCtrlConnection(ctrl_iface) >= 0) {
-			printf("Reconnected successfully\n");
+			debug("Reconnected successfully");
 			pingsToStatusUpdate = 0;
 		}
 	}
@@ -829,6 +861,53 @@
 }
 
 
+void WpaGui::signalMeterUpdate()
+{
+	char reply[128];
+	size_t reply_len = sizeof(reply);
+	char *rssi;
+	int rssi_value;
+
+	ctrlRequest("SIGNAL_POLL", reply, &reply_len);
+
+	/* In order to eliminate signal strength fluctuations, try
+	 * to obtain averaged RSSI value in the first place. */
+	if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL)
+		rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]);
+	else if ((rssi = strstr(reply, "RSSI=")) != NULL)
+		rssi_value = atoi(&rssi[sizeof("RSSI")]);
+	else {
+		debug("Failed to get RSSI value");
+		updateTrayIcon(TrayIconSignalNone);
+		return;
+	}
+
+	debug("RSSI value: %d", rssi_value);
+
+	/*
+	 * NOTE: The code below assumes, that the unit of the value returned
+	 * by the SIGNAL POLL request is dBm. It might not be true for all
+	 * wpa_supplicant drivers.
+	 */
+
+	/*
+	 * Calibration is based on "various Internet sources". Nonetheless,
+	 * it seems to be compatible with the Windows 8.1 strength meter -
+	 * tested on Intel Centrino Advanced-N 6235.
+	 */
+	if (rssi_value >= -60)
+		updateTrayIcon(TrayIconSignalExcellent);
+	else if (rssi_value >= -68)
+		updateTrayIcon(TrayIconSignalGood);
+	else if (rssi_value >= -76)
+		updateTrayIcon(TrayIconSignalOk);
+	else if (rssi_value >= -84)
+		updateTrayIcon(TrayIconSignalWeak);
+	else
+		updateTrayIcon(TrayIconSignalNone);
+}
+
+
 static int str_match(const char *a, const char *b)
 {
 	return strncmp(a, b, strlen(b)) == 0;
@@ -1002,8 +1081,8 @@
 	if (cmd.contains(QRegExp("^\\d+:")))
 		cmd.truncate(cmd.indexOf(':'));
 	else if (!cmd.startsWith("all")) {
-		printf("Invalid editNetwork '%s'\n",
-		       cmd.toAscii().constData());
+		debug("Invalid editNetwork '%s'",
+		      cmd.toAscii().constData());
 		return;
 	}
 	cmd.prepend("ENABLE_NETWORK ");
@@ -1021,8 +1100,8 @@
 	if (cmd.contains(QRegExp("^\\d+:")))
 		cmd.truncate(cmd.indexOf(':'));
 	else if (!cmd.startsWith("all")) {
-		printf("Invalid editNetwork '%s'\n",
-		       cmd.toAscii().constData());
+		debug("Invalid editNetwork '%s'",
+		      cmd.toAscii().constData());
 		return;
 	}
 	cmd.prepend("DISABLE_NETWORK ");
@@ -1111,8 +1190,8 @@
 	if (cmd.contains(QRegExp("^\\d+:")))
 		cmd.truncate(cmd.indexOf(':'));
 	else if (!cmd.startsWith("all")) {
-		printf("Invalid editNetwork '%s'\n",
-		       cmd.toAscii().constData());
+		debug("Invalid editNetwork '%s'",
+		      cmd.toAscii().constData());
 		return;
 	}
 	cmd.prepend("REMOVE_NETWORK ");
@@ -1175,8 +1254,8 @@
 	size_t reply_len = sizeof(reply) - 1;
 	int pos = cmd.indexOf(':');
 	if (pos < 0) {
-		printf("Invalid getNetworkDisabled '%s'\n",
-		       cmd.toAscii().constData());
+		debug("Invalid getNetworkDisabled '%s'",
+		      cmd.toAscii().constData());
 		return -1;
 	}
 	cmd.truncate(pos);
@@ -1267,8 +1346,8 @@
 void WpaGui::selectAdapter( const QString & sel )
 {
 	if (openCtrlConnection(sel.toAscii().constData()) < 0)
-		printf("Failed to open control connection to "
-		       "wpa_supplicant.\n");
+		debug("Failed to open control connection to "
+		      "wpa_supplicant.");
 	updateStatus();
 	updateNetworks();
 }
@@ -1279,10 +1358,7 @@
 	QApplication::setQuitOnLastWindowClosed(false);
 
 	tray_icon = new QSystemTrayIcon(this);
-	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
-		tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
-	else
-		tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
+	updateTrayIcon(TrayIconOffline);
 
 	connect(tray_icon,
 		SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
@@ -1422,6 +1498,59 @@
 }
 
 
+void WpaGui::updateTrayIcon(TrayIconType type)
+{
+	if (!tray_icon || currentIconType == type)
+		return;
+
+	QIcon icon;
+	QIcon fallback_icon;
+
+	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
+		fallback_icon = QIcon(":/icons/wpa_gui.svg");
+	else
+		fallback_icon = QIcon(":/icons/wpa_gui.png");
+
+	switch (type) {
+	case TrayIconOffline:
+		icon = QIcon::fromTheme("network-wireless-offline",
+					fallback_icon);
+		break;
+	case TrayIconAcquiring:
+		icon = QIcon::fromTheme("network-wireless-acquiring",
+					fallback_icon);
+		break;
+	case TrayIconConnected:
+		icon = QIcon::fromTheme("network-wireless-connected",
+					fallback_icon);
+		break;
+	case TrayIconSignalNone:
+		icon = QIcon::fromTheme("network-wireless-signal-none",
+					fallback_icon);
+		break;
+	case TrayIconSignalWeak:
+		icon = QIcon::fromTheme("network-wireless-signal-weak",
+					fallback_icon);
+		break;
+	case TrayIconSignalOk:
+		icon = QIcon::fromTheme("network-wireless-signal-ok",
+					fallback_icon);
+		break;
+	case TrayIconSignalGood:
+		icon = QIcon::fromTheme("network-wireless-signal-good",
+					fallback_icon);
+		break;
+	case TrayIconSignalExcellent:
+		icon = QIcon::fromTheme("network-wireless-signal-excellent",
+					fallback_icon);
+		break;
+	}
+
+	currentIconType = type;
+	tray_icon->setIcon(icon);
+}
+
+
 void WpaGui::closeEvent(QCloseEvent *event)
 {
 	if (eh) {
@@ -1700,13 +1829,13 @@
 
 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
 	if (!scm) {
-		printf("OpenSCManager failed: %d\n", (int) GetLastError());
+		debug("OpenSCManager failed: %d", (int) GetLastError());
 		return false;
 	}
 
 	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
 	if (!svc) {
-		printf("OpenService failed: %d\n\n", (int) GetLastError());
+		debug("OpenService failed: %d", (int) GetLastError());
 		CloseServiceHandle(scm);
 		return false;
 	}
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
index 026eacb..c0de67b 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -22,6 +22,18 @@
 	Q_OBJECT
 
 public:
+
+	enum TrayIconType {
+		TrayIconOffline = 0,
+		TrayIconAcquiring,
+		TrayIconConnected,
+		TrayIconSignalNone,
+		TrayIconSignalWeak,
+		TrayIconSignalOk,
+		TrayIconSignalGood,
+		TrayIconSignalExcellent,
+	};
+
 	WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0,
 	       Qt::WFlags fl = 0);
 	~WpaGui();
@@ -49,6 +61,7 @@
 	virtual void scan();
 	virtual void eventHistory();
 	virtual void ping();
+	virtual void signalMeterUpdate();
 	virtual void processMsg(char *msg);
 	virtual void processCtrlReq(const char *req);
 	virtual void receiveMsgs();
@@ -70,6 +83,7 @@
 	virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
 				     int sec, const QString &msg);
 	virtual void showTrayStatus();
+	virtual void updateTrayIcon(TrayIconType type);
 	virtual void updateTrayToolTip(const QString &msg);
 	virtual void wpsDialog();
 	virtual void peersDialog();
@@ -113,6 +127,7 @@
 	QAction *quitAction;
 	QMenu *tray_menu;
 	QSystemTrayIcon *tray_icon;
+	TrayIconType currentIconType;
 	QString wpaStateTranslate(char *state);
 	void createTrayIcon(bool);
 	bool ackTrayIcon;
@@ -127,6 +142,9 @@
 
 	void stopWpsRun(bool success);
 
+	QTimer *signalMeterTimer;
+	int signalMeterInterval;
+
 #ifdef CONFIG_NATIVE_WINDOWS
 	QAction *fileStartServiceAction;
 	QAction *fileStopServiceAction;
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index ac38d69..6bd60b9 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -199,7 +199,7 @@
 	if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])
 		params.bssid = bssid;
 	params.ssid = assoc->ssid;
-	if (assoc->ssid_len > 32)
+	if (assoc->ssid_len > SSID_MAX_LEN)
 		return;
 	params.ssid_len = assoc->ssid_len;
 	params.freq.mode = assoc->hwmode;
@@ -244,7 +244,7 @@
 static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
 				  struct sockaddr_un *from)
 {
-	u8 ssid[sizeof(int) + 32];
+	u8 ssid[sizeof(int) + SSID_MAX_LEN];
 	int res;
 
 	if (iface->drv_priv == NULL)
@@ -254,7 +254,7 @@
 		goto fail;
 
 	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
-	if (res < 0 || res > 32)
+	if (res < 0 || res > SSID_MAX_LEN)
 		goto fail;
 	os_memcpy(ssid, &res, sizeof(int));
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 21f4af5..b96fd8e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -33,6 +33,7 @@
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
 #include "p2p/p2p.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
@@ -56,7 +57,7 @@
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -438,6 +439,7 @@
 	wpa_tdls_deinit(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
 
+	wmm_ac_clear_saved_tspecs(wpa_s);
 	pmksa_candidate_free(wpa_s->wpa);
 	wpa_sm_deinit(wpa_s->wpa);
 	wpa_s->wpa = NULL;
@@ -454,6 +456,8 @@
 			     wpa_s, NULL);
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
+	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+
 	wpas_wps_deinit(wpa_s);
 
 	wpabuf_free(wpa_s->pending_eapol_rx);
@@ -487,6 +491,8 @@
 	os_free(wpa_s->manual_sched_scan_freqs);
 	wpa_s->manual_sched_scan_freqs = NULL;
 
+	wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
+
 	gas_query_deinit(wpa_s->gas);
 	wpa_s->gas = NULL;
 
@@ -725,6 +731,7 @@
 			ssid && ssid->id_str ? ssid->id_str : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+		wpa_blacklist_clear(wpa_s);
 		wpa_s->extra_blacklist_count = 0;
 		wpa_s->new_connection = 0;
 		wpa_drv_set_operstate(wpa_s, 1);
@@ -760,6 +767,9 @@
 	if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
 		wpa_supplicant_start_autoscan(wpa_s);
 
+	if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
+		wmm_ac_notify_disassoc(wpa_s);
+
 	if (wpa_s->wpa_state != old_state) {
 		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
@@ -863,6 +873,7 @@
 
 	eapol_sm_invalidate_cached_session(wpa_s->eapol);
 	if (wpa_s->current_ssid) {
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	}
@@ -955,9 +966,7 @@
 
 #ifdef CONFIG_IEEE80211W
 	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-	     wpa_s->conf->pmf : ssid->ieee80211w) ==
-	    MGMT_FRAME_PROTECTION_REQUIRED) {
+	    wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
 			"that does not support management frame protection - "
 			"reject");
@@ -1131,10 +1140,18 @@
 		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
 	if (0) {
+#ifdef CONFIG_SUITEB192
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_SUITEB
 	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"WPA: using KEY_MGMT 802.1X with Suite B");
+#endif /* CONFIG_SUITEB */
 #ifdef CONFIG_IEEE80211R
 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1188,8 +1205,7 @@
 
 #ifdef CONFIG_IEEE80211W
 	sel = ie.mgmt_group_cipher;
-	if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+	if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
 	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
 		sel = 0;
 	if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1215,8 +1231,7 @@
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
 			 wpa_s->mgmt_group_cipher);
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
-			 (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-			  wpa_s->conf->pmf : ssid->ieee80211w));
+			 wpas_get_ssid_pmf(wpa_s, ssid));
 #endif /* CONFIG_IEEE80211W */
 
 	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1225,7 +1240,12 @@
 	}
 
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
-		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+		int psk_set = 0;
+
+		if (ssid->psk_set) {
+			wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+			psk_set = 1;
+		}
 #ifndef CONFIG_NO_PBKDF2
 		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
 		    ssid->passphrase) {
@@ -1235,6 +1255,7 @@
 		        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
 					psk, PMK_LEN);
 			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+			psk_set = 1;
 			os_memset(psk, 0, sizeof(psk));
 		}
 #endif /* CONFIG_NO_PBKDF2 */
@@ -1272,6 +1293,7 @@
 						"external passphrase)",
 						psk, PMK_LEN);
 				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+				psk_set = 1;
 				os_memset(psk, 0, sizeof(psk));
 			} else
 #endif /* CONFIG_NO_PBKDF2 */
@@ -1284,6 +1306,7 @@
 					return -1;
 				}
 				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+				psk_set = 1;
 				os_memset(psk, 0, sizeof(psk));
 			} else {
 				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
@@ -1297,6 +1320,12 @@
 			ext_password_free(pw);
 		}
 #endif /* CONFIG_EXT_PASSWORD */
+
+		if (!psk_set) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"No PSK available for association");
+			return -1;
+		}
 	} else
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
@@ -1526,8 +1555,15 @@
 	else
 		rand_style = ssid->mac_addr;
 
+	wmm_ac_clear_saved_tspecs(wpa_s);
+	wpa_s->reassoc_same_bss = 0;
+
 	if (wpa_s->last_ssid == ssid) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+		if (wpa_s->current_bss && wpa_s->current_bss == bss) {
+			wmm_ac_save_tspecs(wpa_s);
+			wpa_s->reassoc_same_bss = 1;
+		}
 	} else if (rand_style > 0) {
 		if (wpas_update_random_addr(wpa_s, rand_style) < 0)
 			return;
@@ -1636,6 +1672,227 @@
 }
 
 
+static int bss_is_ibss(struct wpa_bss *bss)
+{
+	return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+		IEEE80211_CAP_IBSS;
+}
+
+
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+			  const struct wpa_ssid *ssid,
+			  struct hostapd_freq_params *freq)
+{
+	enum hostapd_hw_mode hw_mode;
+	struct hostapd_hw_modes *mode = NULL;
+	int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			   184, 192 };
+	int vht80[] = { 36, 52, 100, 116, 132, 149 };
+	struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+	u8 channel;
+	int i, chan_idx, ht40 = -1, res, obss_scan = 1;
+	unsigned int j;
+	struct hostapd_freq_params vht_freq;
+
+	freq->freq = ssid->frequency;
+
+	for (j = 0; j < wpa_s->last_scan_res_used; j++) {
+		struct wpa_bss *bss = wpa_s->last_scan_res[j];
+
+		if (ssid->mode != WPAS_MODE_IBSS)
+			break;
+
+		/* Don't adjust control freq in case of fixed_freq */
+		if (ssid->fixed_freq)
+			break;
+
+		if (!bss_is_ibss(bss))
+			continue;
+
+		if (ssid->ssid_len == bss->ssid_len &&
+		    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "IBSS already found in scan results, adjust control freq: %d",
+				   bss->freq);
+			freq->freq = bss->freq;
+			obss_scan = 0;
+			break;
+		}
+	}
+
+	/* For IBSS check HT_IBSS flag */
+	if (ssid->mode == WPAS_MODE_IBSS &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
+		return;
+
+	if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
+	    wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
+	    wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_DEBUG,
+			   "IBSS: WEP/TKIP detected, do not try to enable HT");
+		return;
+	}
+
+	hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+	for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+		if (wpa_s->hw.modes[i].mode == hw_mode) {
+			mode = &wpa_s->hw.modes[i];
+			break;
+		}
+	}
+
+	if (!mode)
+		return;
+
+	freq->ht_enabled = ht_supported(mode);
+	if (!freq->ht_enabled)
+		return;
+
+	/* Setup higher BW only for 5 GHz */
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return;
+
+	for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
+		pri_chan = &mode->channels[chan_idx];
+		if (pri_chan->chan == channel)
+			break;
+		pri_chan = NULL;
+	}
+	if (!pri_chan)
+		return;
+
+	/* Check primary channel flags */
+	if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+		return;
+
+	/* Check/setup HT40+/HT40- */
+	for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
+		if (ht40plus[j] == channel) {
+			ht40 = 1;
+			break;
+		}
+	}
+
+	/* Find secondary channel */
+	for (i = 0; i < mode->num_channels; i++) {
+		sec_chan = &mode->channels[i];
+		if (sec_chan->chan == channel + ht40 * 4)
+			break;
+		sec_chan = NULL;
+	}
+	if (!sec_chan)
+		return;
+
+	/* Check secondary channel flags */
+	if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+		return;
+
+	freq->channel = pri_chan->chan;
+
+	switch (ht40) {
+	case -1:
+		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
+			return;
+		freq->sec_channel_offset = -1;
+		break;
+	case 1:
+		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
+			return;
+		freq->sec_channel_offset = 1;
+		break;
+	default:
+		break;
+	}
+
+	if (freq->sec_channel_offset && obss_scan) {
+		struct wpa_scan_results *scan_res;
+
+		scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+		if (scan_res == NULL) {
+			/* Back to HT20 */
+			freq->sec_channel_offset = 0;
+			return;
+		}
+
+		res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
+				     sec_chan->chan);
+		switch (res) {
+		case 0:
+			/* Back to HT20 */
+			freq->sec_channel_offset = 0;
+			break;
+		case 1:
+			/* Configuration allowed */
+			break;
+		case 2:
+			/* Switch pri/sec channels */
+			freq->freq = hw_get_freq(mode, sec_chan->chan);
+			freq->sec_channel_offset = -freq->sec_channel_offset;
+			freq->channel = sec_chan->chan;
+			break;
+		default:
+			freq->sec_channel_offset = 0;
+			break;
+		}
+
+		wpa_scan_results_free(scan_res);
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
+		   freq->channel, freq->sec_channel_offset);
+
+	/* Not sure if mesh is ready for VHT */
+	if (ssid->mode != WPAS_MODE_IBSS)
+		return;
+
+	/* For IBSS check VHT_IBSS flag */
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+		return;
+
+	vht_freq = *freq;
+
+	vht_freq.vht_enabled = vht_supported(mode);
+	if (!vht_freq.vht_enabled)
+		return;
+
+	/* setup center_freq1, bandwidth */
+	for (j = 0; j < ARRAY_SIZE(vht80); j++) {
+		if (freq->channel >= vht80[j] &&
+		    freq->channel < vht80[j] + 16)
+			break;
+	}
+
+	if (j == ARRAY_SIZE(vht80))
+		return;
+
+	for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
+		struct hostapd_channel_data *chan;
+
+		chan = hw_get_channel_chan(mode, i, NULL);
+		if (!chan)
+			return;
+
+		/* Back to HT configuration if channel not usable */
+		if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+			return;
+	}
+
+	if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
+				    freq->channel, freq->ht_enabled,
+				    vht_freq.vht_enabled,
+				    freq->sec_channel_offset,
+				    VHT_CHANWIDTH_80MHZ,
+				    vht80[j] + 6, 0, 0) != 0)
+		return;
+
+	*freq = vht_freq;
+
+	wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
+		   freq->center_freq1, freq->center_freq2, freq->bandwidth);
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 {
 	struct wpa_connect_work *cwork = work->ctx;
@@ -1757,7 +2014,7 @@
 			(ssid->proto & WPA_PROTO_RSN);
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    ssid, try_opportunistic) == 0)
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 		wpa_ie_len = sizeof(wpa_ie);
 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
 					      wpa_ie, &wpa_ie_len)) {
@@ -1884,6 +2141,18 @@
 		}
 	}
 
+	if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+		struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+		size_t len;
+
+		len = sizeof(wpa_ie) - wpa_ie_len;
+		if (wpabuf_len(buf) <= len) {
+			os_memcpy(wpa_ie + wpa_ie_len,
+				  wpabuf_head(buf), wpabuf_len(buf));
+			wpa_ie_len += wpabuf_len(buf);
+		}
+	}
+
 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
 	use_crypt = 1;
 	cipher_pairwise = wpa_s->pairwise_cipher;
@@ -1949,25 +2218,11 @@
 
 	/* Initial frequency for IBSS/mesh */
 	if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
-	    ssid->frequency > 0 && params.freq.freq == 0) {
-		enum hostapd_hw_mode hw_mode;
-		u8 channel;
-
-		params.freq.freq = ssid->frequency;
-
-		hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
-		for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
-			if (wpa_s->hw.modes[i].mode == hw_mode) {
-				struct hostapd_hw_modes *mode;
-
-				mode = &wpa_s->hw.modes[i];
-				params.freq.ht_enabled = ht_supported(mode);
-				break;
-			}
-		}
-	}
+	    ssid->frequency > 0 && params.freq.freq == 0)
+		ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
 
 	if (ssid->mode == WPAS_MODE_IBSS) {
+		params.fixed_freq = ssid->fixed_freq;
 		if (ssid->beacon_int)
 			params.beacon_int = ssid->beacon_int;
 		else
@@ -2001,7 +2256,8 @@
 	if (wpa_s->conf->key_mgmt_offload) {
 		if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
 		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
-		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
 			params.req_key_mgmt_offload =
 				ssid->proactive_key_caching < 0 ?
 				wpa_s->conf->okc : ssid->proactive_key_caching;
@@ -2018,9 +2274,7 @@
 	params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-	params.mgmt_frame_protection =
-		ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
-		wpa_s->conf->pmf : ssid->ieee80211w;
+	params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
 	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
 		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 		struct wpa_ie_data ie;
@@ -2054,7 +2308,7 @@
 	os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
 	params.vhtcaps = &vhtcaps;
 	params.vhtcaps_mask = &vhtcaps_mask;
-	wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+	wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_VHT_OVERRIDES */
 
 #ifdef CONFIG_P2P
@@ -2349,6 +2603,7 @@
 	int disconnected = 0;
 
 	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(
 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		disconnected = 1;
@@ -2387,6 +2642,13 @@
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 		wpa_s->connect_without_scan =
 			(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+
+		/*
+		 * Don't optimize next scan freqs since a new ESS has been
+		 * selected.
+		 */
+		os_free(wpa_s->next_scan_freqs);
+		wpa_s->next_scan_freqs = NULL;
 	} else {
 		wpa_s->connect_without_scan = NULL;
 	}
@@ -2610,7 +2872,7 @@
 struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_ssid *entry;
-	u8 ssid[MAX_SSID_LEN];
+	u8 ssid[SSID_MAX_LEN];
 	int res;
 	size_t ssid_len;
 	u8 bssid[ETH_ALEN];
@@ -2941,11 +3203,9 @@
 	if (wpa_s->bridge_ifname[0]) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
 			"interface '%s'", wpa_s->bridge_ifname);
-		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
-					      wpa_s->own_addr,
-					      ETH_P_EAPOL,
-					      wpa_supplicant_rx_eapol_bridge,
-					      wpa_s, 1);
+		wpa_s->l2_br = l2_packet_init_bridge(
+			wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+			ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
 		if (wpa_s->l2_br == NULL) {
 			wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
 				"connection for the bridge interface '%s'",
@@ -2994,7 +3254,8 @@
 }
 
 
-static struct wpa_supplicant * wpa_supplicant_alloc(void)
+static struct wpa_supplicant *
+wpa_supplicant_alloc(struct wpa_supplicant *parent)
 {
 	struct wpa_supplicant *wpa_s;
 
@@ -3004,7 +3265,7 @@
 	wpa_s->scan_req = INITIAL_SCAN_REQ;
 	wpa_s->scan_interval = 5;
 	wpa_s->new_connection = 1;
-	wpa_s->parent = wpa_s;
+	wpa_s->parent = parent ? parent : wpa_s;
 	wpa_s->sched_scanning = 0;
 
 	return wpa_s;
@@ -3469,7 +3730,7 @@
 
 	wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
 			      radio_list);
-	if (wpa_s && wpa_s->external_scan_running) {
+	if (wpa_s && wpa_s->radio->external_scan_running) {
 		wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
 		return;
 	}
@@ -3837,6 +4098,23 @@
 	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
 						      &wpa_s->hw.num_modes,
 						      &wpa_s->hw.flags);
+	if (wpa_s->hw.modes) {
+		u16 i;
+
+		for (i = 0; i < wpa_s->hw.num_modes; i++) {
+			if (wpa_s->hw.modes[i].vht_capab) {
+				wpa_s->hw_capab = CAPAB_VHT;
+				break;
+			}
+
+			if (wpa_s->hw.modes[i].ht_capab &
+			    HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+				wpa_s->hw_capab = CAPAB_HT40;
+			else if (wpa_s->hw.modes[i].ht_capab &&
+				 wpa_s->hw_capab == CAPAB_NO_HT_VHT)
+				wpa_s->hw_capab = CAPAB_HT;
+		}
+	}
 
 	capa_res = wpa_drv_get_capa(wpa_s, &capa);
 	if (capa_res == 0) {
@@ -3858,6 +4136,13 @@
 		wpa_s->num_multichan_concurrent =
 			capa.num_multichan_concurrent;
 		wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+
+		if (capa.mac_addr_rand_scan_supported)
+			wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
+		if (wpa_s->sched_scan_supported &&
+		    capa.mac_addr_rand_sched_scan_supported)
+			wpa_s->mac_addr_rand_supported |=
+				(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
 	}
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;
@@ -4034,6 +4319,7 @@
  * wpa_supplicant_add_iface - Add a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * @iface: Interface configuration options
+ * @parent: Parent interface or %NULL to assign new interface as parent
  * Returns: Pointer to the created interface or %NULL on failure
  *
  * This function is used to add new network interfaces for %wpa_supplicant.
@@ -4043,7 +4329,8 @@
  * e.g., when a hotplug network adapter is inserted.
  */
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
-						 struct wpa_interface *iface)
+						 struct wpa_interface *iface,
+						 struct wpa_supplicant *parent)
 {
 	struct wpa_supplicant *wpa_s;
 	struct wpa_interface t_iface;
@@ -4052,7 +4339,7 @@
 	if (global == NULL || iface == NULL)
 		return NULL;
 
-	wpa_s = wpa_supplicant_alloc();
+	wpa_s = wpa_supplicant_alloc(parent);
 	if (wpa_s == NULL)
 		return NULL;
 
@@ -4534,11 +4821,17 @@
 	 */
 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
 
+	/*
+	 * There is no point in blacklisting the AP if this event is
+	 * generated based on local request to disconnect.
+	 */
+	if (wpa_s->own_disconnect_req) {
+		wpa_s->own_disconnect_req = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Ignore connection failure due to local request to disconnect");
+		return;
+	}
 	if (wpa_s->disconnected) {
-		/*
-		 * There is no point in blacklisting the AP if this event is
-		 * generated based on local request to disconnect.
-		 */
 		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
 			"indication since interface has been put into "
 			"disconnected state");
@@ -4689,6 +4982,15 @@
 		str_clear_free(eap->external_sim_resp);
 		eap->external_sim_resp = os_strdup(value);
 		break;
+	case WPA_CTRL_REQ_PSK_PASSPHRASE:
+		if (wpa_config_set(ssid, "psk", value, 0) < 0)
+			return -1;
+		ssid->mem_only_psk = 1;
+		if (ssid->passphrase)
+			wpa_config_update_psk(ssid);
+		if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
 		return -1;
@@ -4708,13 +5010,16 @@
 	int i;
 	unsigned int drv_enc;
 
+	if (wpa_s->p2p_mgmt)
+		return 1; /* no normal network profiles on p2p_mgmt interface */
+
 	if (ssid == NULL)
 		return 1;
 
 	if (ssid->disabled)
 		return 1;
 
-	if (wpa_s && wpa_s->drv_capa_known)
+	if (wpa_s->drv_capa_known)
 		drv_enc = wpa_s->drv_enc;
 	else
 		drv_enc = (unsigned int) -1;
@@ -4733,13 +5038,38 @@
 	}
 
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
-	    (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
+	    (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
+	    !ssid->mem_only_psk)
 		return 1;
 
 	return 0;
 }
 
 
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_IEEE80211W
+	if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+		if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
+		    !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
+			/*
+			 * Driver does not support BIP -- ignore pmf=1 default
+			 * since the connection with PMF would fail and the
+			 * configuration does not require PMF to be enabled.
+			 */
+			return NO_MGMT_FRAME_PROTECTION;
+		}
+
+		return wpa_s->conf->pmf;
+	}
+
+	return ssid->ieee80211w;
+#else /* CONFIG_IEEE80211W */
+	return NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
@@ -4883,6 +5213,8 @@
 
 	if (wpa_supplicant_fast_associate(wpa_s) != 1)
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	else
+		wpa_s->reattach = 0;
 }
 
 
@@ -5060,6 +5392,13 @@
 }
 
 
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+/* Workaround different, undefined for Windows, error codes used here */
+#define ENOTCONN -1
+#define EOPNOTSUPP -1
+#define ECANCELED -1
+#endif
+
 /**
  * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
  * @wpa_s: Pointer to wpa_supplicant
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index e78c0dd..eb7434a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -127,6 +127,17 @@
 # Maximum number of mesh peering currently maintained by the STA.
 #max_peer_links=99
 
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in mesh STA to clean up inactive stations.
+#mesh_max_inactivity=300
+
+# cert_in_cb - Whether to include a peer certificate dump in events
+# This controls whether peer certificates for authentication server and
+# its certificate chain are included in EAP peer certificate events. This is
+# enabled by default.
+#cert_in_cb=1
+
 # EAP fast re-authentication
 # By default, fast re-authentication is enabled for all EAP methods that
 # support it. This variable can be used to disable fast re-authentication.
@@ -729,6 +740,11 @@
 # startup and reconfiguration time can be optimized by generating the PSK only
 # only when the passphrase or SSID has actually changed.
 #
+# mem_only_psk: Whether to keep PSK/passphrase only in memory
+# 0 = allow psk/passphrase to be stored to the configuration file
+# 1 = do not store psk/passphrase to the configuration file
+#mem_only_psk=0
+#
 # eapol_flags: IEEE 802.1X/EAPOL options (bit field)
 # Dynamic WEP key required for non-WPA mode
 # bit0 (1): require dynamically generated unicast WEP key
@@ -865,6 +881,10 @@
 #	sertificate is only accepted if it contains this string in the subject.
 #	The subject string is in following format:
 #	/C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+#	Note: Since this is a substring match, this cannot be used securily to
+#	do a suffix match against a possible domain name in the CN entry. For
+#	such a use case, domain_suffix_match or domain_match should be used
+#	instead.
 # altsubject_match: Semicolon separated string of entries to be matched against
 #	the alternative subject name of the authentication server certificate.
 #	If this string is set, the server sertificate is only accepted if it
@@ -873,6 +893,30 @@
 #	Example: EMAIL:server@example.com
 #	Example: DNS:server.example.com;DNS:server2.example.com
 #	Following types are supported: EMAIL, DNS, URI
+# domain_suffix_match: Constraint for server domain name. If set, this FQDN is
+#	used as a suffix match requirement for the AAAserver certificate in
+#	SubjectAltName dNSName element(s). If a matching dNSName is found, this
+#	constraint is met. If no dNSName values are present, this constraint is
+#	matched against SubjectName CN using same suffix match comparison.
+#
+#	Suffix match here means that the host/domain name is compared one label
+#	at a time starting from the top-level domain and all the labels in
+#	domain_suffix_match shall be included in the certificate. The
+#	certificate may include additional sub-level labels in addition to the
+#	required labels.
+#
+#	For example, domain_suffix_match=example.com would match
+#	test.example.com but would not match test-example.com.
+# domain_match: Constraint for server domain name
+#	If set, this FQDN is used as a full match requirement for the
+#	server certificate in SubjectAltName dNSName element(s). If a
+#	matching dNSName is found, this constraint is met. If no dNSName
+#	values are present, this constraint is matched against SubjectName CN
+#	using same full match comparison. This behavior is similar to
+#	domain_suffix_match, but has the requirement of a full match, i.e.,
+#	no subdomains or wildcard matches are allowed. Case-insensitive
+#	comparison is used, so "Example.com" matches "example.com", but would
+#	not match "test.Example.com".
 # phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
 #	(string with field-value pairs, e.g., "peapver=0" or
 #	"peapver=1 peaplabel=1")
@@ -901,9 +945,20 @@
 #	 * 2 = require cryptobinding
 #	EAP-WSC (WPS) uses following options: pin=<Device Password> or
 #	pbc=1.
+#
+#	For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+#	used to configure a mode that allows EAP-Success (and EAP-Failure)
+#	without going through authentication step. Some switches use such
+#	sequence when forcing the port to be authorized/unauthorized or as a
+#	fallback option if the authentication server is unreachable. By default,
+#	wpa_supplicant discards such frames to protect against potential attacks
+#	by rogue devices, but this option can be used to disable that protection
+#	for cases where the server/authenticator does not need to be
+#	authenticated.
 # 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)
+#	"autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS). "mschapv2_retry=0" can be
+#	used to disable MSCHAPv2 password retry in authentication failure cases.
 #
 # 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
@@ -919,7 +974,7 @@
 # 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.
+#	EAP workarounds are disabled with eap_workaround=0.
 #	For EAP-FAST, this must be set to 0 (or left unconfigured for the
 #	default value to be used automatically).
 # tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers
@@ -939,9 +994,12 @@
 # private_key2_passwd: Password for private key file
 # dh_file2: File path to DH/DSA parameters file (in PEM format)
 # subject_match2: Substring to be matched against the subject of the
-#	authentication server certificate.
-# altsubject_match2: Substring to be matched against the alternative subject
-#	name of the authentication server certificate.
+#	authentication server certificate. See subject_match for more details.
+# altsubject_match2: Semicolon separated string of entries to be matched
+#	against the alternative subject name of the authentication server
+#	certificate. See altsubject_match documentation for more details.
+# domain_suffix_match2: Constraint for server domain name. See
+#	domain_suffix_match for more details.
 #
 # fragment_size: Maximum EAP fragment size in bytes (default 1398).
 #	This value limits the fragment size for EAP methods that support
@@ -1431,6 +1489,21 @@
 	key_mgmt=NONE
 }
 
+# Example configuration blacklisting two APs - these will be ignored
+# for this network.
+network={
+	ssid="example"
+	psk="very secret passphrase"
+	bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
+}
+
+# Example configuration limiting AP selection to a specific set of APs;
+# any other AP not matching the masked address will be ignored.
+network={
+	ssid="example"
+	psk="very secret passphrase"
+	bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
+}
 
 # Example config file that will only scan on channel 36.
 freq_list=5180
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 52137d4..1b9753c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -275,6 +275,8 @@
 	unsigned int p2p_per_sta_psk:1;
 	unsigned int p2p_fail_on_wps_complete:1;
 	unsigned int p2p_24ghz_social_channels:1;
+	unsigned int pending_p2ps_group:1;
+	unsigned int pending_group_iface_for_p2ps:1;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	int wifi_display;
@@ -296,6 +298,7 @@
 struct wpa_radio {
 	char name[16]; /* from driver_ops get_radio_name() or empty if not
 			* available */
+	unsigned int external_scan_running:1;
 	struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
 	struct dl_list work; /* struct wpa_radio_work::list entries */
 };
@@ -366,7 +369,7 @@
 };
 
 struct wpa_ssid_value {
-	u8 ssid[32];
+	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
 };
 
@@ -403,6 +406,11 @@
 	u8 next_neighbor_rep_token;
 };
 
+enum wpa_supplicant_test_failure {
+	WPAS_TEST_FAILURE_NONE,
+	WPAS_TEST_FAILURE_SCAN_TRIGGER,
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -444,6 +452,7 @@
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
+	int reassoc_same_bss; /* reassociating to the same bss */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
 			   * before this has been cleared */
 	struct wpa_ssid *current_ssid;
@@ -579,6 +588,7 @@
 		 */
 		MANUAL_SCAN_REQ
 	} scan_req, last_scan_req;
+	enum wpa_states scan_prev_wpa_state;
 	struct os_reltime scan_trigger_time, scan_start_time;
 	int scan_runs; /* number of scan runs since WPS was started */
 	int *next_scan_freqs;
@@ -589,7 +599,6 @@
 	unsigned int manual_scan_only_new:1;
 	unsigned int own_scan_requested:1;
 	unsigned int own_scan_running:1;
-	unsigned int external_scan_running:1;
 	unsigned int clear_driver_scan_cache:1;
 	unsigned int manual_scan_id;
 	int scan_interval; /* time in sec between scans to find suitable AP */
@@ -639,6 +648,7 @@
 	unsigned int eap_expected_failure:1;
 	unsigned int reattach:1; /* reassociation to the same BSS requested */
 	unsigned int mac_addr_changed:1;
+	unsigned int added_vif:1;
 
 	struct os_reltime last_mac_addr_change;
 	int last_mac_addr_style;
@@ -652,7 +662,7 @@
 
 #ifdef CONFIG_SME
 	struct {
-		u8 ssid[32];
+		u8 ssid[SSID_MAX_LEN];
 		size_t ssid_len;
 		int freq;
 		u8 assoc_req_ie[200];
@@ -702,6 +712,8 @@
 	struct mesh_rsn *mesh_rsn;
 	int mesh_if_idx;
 	unsigned int mesh_if_created:1;
+	unsigned int mesh_ht_enabled:1;
+	int mesh_auth_block_duration; /* sec */
 #endif /* CONFIG_MESH */
 
 	unsigned int off_channel_freq;
@@ -756,14 +768,14 @@
 	u8 pending_join_iface_addr[ETH_ALEN];
 	u8 pending_join_dev_addr[ETH_ALEN];
 	int pending_join_wps_method;
-	u8 p2p_join_ssid[32];
+	u8 p2p_join_ssid[SSID_MAX_LEN];
 	size_t p2p_join_ssid_len;
 	int p2p_join_scan_count;
 	int auto_pd_scan_retry;
 	int force_long_sd;
 	u16 pending_pd_config_methods;
 	enum {
-		NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+		NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN, AUTO_PD_ASP
 	} pending_pd_use;
 
 	/*
@@ -802,6 +814,7 @@
 	unsigned int p2p_nfc_tag_enabled:1;
 	unsigned int p2p_peer_oob_pk_hash_known:1;
 	unsigned int p2p_disable_ip_addr_req:1;
+	unsigned int p2ps_join_addr_valid:1;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
@@ -821,6 +834,7 @@
 	/* group common frequencies */
 	int *p2p_group_common_freqs;
 	unsigned int p2p_group_common_freqs_num;
+	u8 p2ps_join_addr[ETH_ALEN];
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;
@@ -855,6 +869,7 @@
 	unsigned int network_select:1;
 	unsigned int auto_select:1;
 	unsigned int auto_network_select:1;
+	unsigned int interworking_fast_assoc_tried:1;
 	unsigned int fetch_all_anqp:1;
 	unsigned int fetch_osu_info:1;
 	unsigned int fetch_osu_waiting_scan:1;
@@ -874,6 +889,12 @@
 		u16 num_modes;
 		u16 flags;
 	} hw;
+	enum local_hw_capab {
+		CAPAB_NO_HT_VHT,
+		CAPAB_HT,
+		CAPAB_HT40,
+		CAPAB_VHT,
+	} hw_capab;
 #ifdef CONFIG_MACSEC
 	struct ieee802_1x_kay *kay;
 #endif /* CONFIG_MACSEC */
@@ -895,6 +916,21 @@
 	unsigned int ext_eapol_frame_io:1;
 	unsigned int wmm_ac_supported:1;
 	unsigned int ext_work_in_progress:1;
+	unsigned int own_disconnect_req:1;
+
+#define MAC_ADDR_RAND_SCAN       BIT(0)
+#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
+#define MAC_ADDR_RAND_PNO        BIT(2)
+#define MAC_ADDR_RAND_ALL        (MAC_ADDR_RAND_SCAN | \
+				  MAC_ADDR_RAND_SCHED_SCAN | \
+				  MAC_ADDR_RAND_PNO)
+	unsigned int mac_addr_rand_supported;
+	unsigned int mac_addr_rand_enable;
+
+	/* MAC Address followed by mask (2 * ETH_ALEN) */
+	u8 *mac_addr_scan;
+	u8 *mac_addr_sched_scan;
+	u8 *mac_addr_pno;
 
 #ifdef CONFIG_WNM
 	u8 wnm_dialog_token;
@@ -923,12 +959,15 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	struct l2_packet_data *l2_test;
 	unsigned int extra_roc_dur;
+	enum wpa_supplicant_test_failure test_failure;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	struct wmm_ac_assoc_data *wmm_ac_assoc_info;
 	struct wmm_tspec_element *tspecs[WMM_AC_NUM][TS_DIR_IDX_COUNT];
 	struct wmm_ac_addts_request *addts_request;
 	u8 wmm_ac_last_dialog_token;
+	struct wmm_tspec_element *last_tspecs;
+	u8 last_tspecs_count;
 
 	struct rrm_data rrm;
 };
@@ -997,7 +1036,8 @@
 void wpa_show_license(void);
 
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
-						 struct wpa_interface *iface);
+						 struct wpa_interface *iface,
+						 struct wpa_supplicant *parent);
 int wpa_supplicant_remove_iface(struct wpa_global *global,
 				struct wpa_supplicant *wpa_s,
 				int terminate);
@@ -1057,6 +1097,10 @@
 					      const char *field,
 					      const char *value);
 
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+			  const struct wpa_ssid *ssid,
+			  struct hostapd_freq_params *freq);
+
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
@@ -1083,6 +1127,7 @@
 }
 
 int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
@@ -1096,4 +1141,5 @@
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len);
 
+void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
 #endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 70ece22..48a5d69 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -609,12 +609,14 @@
 #ifdef CONFIG_TDLS
 
 static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
-					int *tdls_ext_setup)
+					int *tdls_ext_setup,
+					int *tdls_chan_switch)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
 	*tdls_supported = 0;
 	*tdls_ext_setup = 0;
+	*tdls_chan_switch = 0;
 
 	if (!wpa_s->drv_capa_known)
 		return -1;
@@ -625,6 +627,9 @@
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
 		*tdls_ext_setup = 1;
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH)
+		*tdls_chan_switch = 1;
+
 	return 0;
 }
 
@@ -692,6 +697,25 @@
 	return wpa_drv_sta_add(wpa_s, &params);
 }
 
+
+static int wpa_supplicant_tdls_enable_channel_switch(
+	void *ctx, const u8 *addr, u8 oper_class,
+	const struct hostapd_freq_params *params)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_drv_tdls_enable_channel_switch(wpa_s, addr, oper_class,
+						  params);
+}
+
+
+static int wpa_supplicant_tdls_disable_channel_switch(void *ctx, const u8 *addr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_drv_tdls_disable_channel_switch(wpa_s, addr);
+}
+
 #endif /* CONFIG_TDLS */
 
 #endif /* CONFIG_NO_WPA */
@@ -713,6 +737,8 @@
 		return WPA_CTRL_REQ_EAP_PASSPHRASE;
 	else if (os_strcmp(field, "SIM") == 0)
 		return WPA_CTRL_REQ_SIM;
+	else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
+		return WPA_CTRL_REQ_PSK_PASSPHRASE;
 	return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -752,6 +778,10 @@
 	case WPA_CTRL_REQ_SIM:
 		ret = "SIM";
 		break;
+	case WPA_CTRL_REQ_PSK_PASSPHRASE:
+		*txt = "PSK or passphrase";
+		ret = "PSK_PASSPHRASE";
+		break;
 	default:
 		break;
 	}
@@ -765,6 +795,35 @@
 	return ret;
 }
 
+
+void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+			const char *field_name, const char *txt)
+{
+	char *buf;
+	size_t buflen;
+	int len;
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen, "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (os_snprintf_error(buflen, len)) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s", buf);
+	os_free(buf);
+}
+
+
 #ifdef IEEE8021X_EAPOL
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 static void wpa_supplicant_eap_param_needed(void *ctx,
@@ -774,9 +833,6 @@
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	const char *field_name, *txt = NULL;
-	char *buf;
-	size_t buflen;
-	int len;
 
 	if (ssid == NULL)
 		return;
@@ -793,31 +849,32 @@
 
 	wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
 
-	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-	len = os_snprintf(buf, buflen,
-			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
-			  field_name, ssid->id, txt);
-	if (os_snprintf_error(buflen, len)) {
-		os_free(buf);
-		return;
-	}
-	if (ssid->ssid && buflen > len + ssid->ssid_len) {
-		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
-		len += ssid->ssid_len;
-		buf[len] = '\0';
-	}
-	buf[buflen - 1] = '\0';
-	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
-	os_free(buf);
+	wpas_send_ctrl_req(wpa_s, ssid, field_name, txt);
 }
 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 #define wpa_supplicant_eap_param_needed NULL
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 
 
+#ifdef CONFIG_EAP_PROXY
+static void wpa_supplicant_eap_proxy_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	size_t len;
+
+	wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+						     wpa_s->imsi, &len);
+	if (wpa_s->mnc_len > 0) {
+		wpa_s->imsi[len] = '\0';
+		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+			   wpa_s->imsi, wpa_s->mnc_len);
+	} else {
+		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+	}
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
 static void wpa_supplicant_port_cb(void *ctx, int authorized)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -836,12 +893,14 @@
 
 
 static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+				   const char *altsubject[], int num_altsubject,
 				   const char *cert_hash,
 				   const struct wpabuf *cert)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+	wpas_notify_certification(wpa_s, depth, subject, altsubject,
+				  num_altsubject, cert_hash, cert);
 }
 
 
@@ -921,9 +980,13 @@
 	ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
 	ctx->wps = wpa_s->wps;
 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
+#ifdef CONFIG_EAP_PROXY
+	ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+#endif /* CONFIG_EAP_PROXY */
 	ctx->port_cb = wpa_supplicant_port_cb;
 	ctx->cb = wpa_supplicant_eapol_cb;
 	ctx->cert_cb = wpa_supplicant_cert_cb;
+	ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
 	ctx->status_cb = wpa_supplicant_status_cb;
 	ctx->set_anon_id = wpa_supplicant_set_anon_id;
 	ctx->cb_ctx = wpa_s;
@@ -941,13 +1004,14 @@
 
 
 #ifndef CONFIG_NO_WPA
-static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
-					     const u8 *kck,
+static void wpa_supplicant_set_rekey_offload(void *ctx,
+					     const u8 *kek, size_t kek_len,
+					     const u8 *kck, size_t kck_len,
 					     const u8 *replay_ctr)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+	wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr);
 }
 #endif /* CONFIG_NO_WPA */
 
@@ -1004,6 +1068,10 @@
 	ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
 	ctx->tdls_oper = wpa_supplicant_tdls_oper;
 	ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+	ctx->tdls_enable_channel_switch =
+		wpa_supplicant_tdls_enable_channel_switch;
+	ctx->tdls_disable_channel_switch =
+		wpa_supplicant_tdls_disable_channel_switch;
 #endif /* CONFIG_TDLS */
 	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 	ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
@@ -1012,6 +1080,7 @@
 	if (wpa_s->wpa == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
 			   "machine");
+		os_free(ctx);
 		return -1;
 	}
 #endif /* CONFIG_NO_WPA */
diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h
index 9808c22..5585e56 100644
--- a/wpa_supplicant/wpas_glue.h
+++ b/wpa_supplicant/wpas_glue.h
@@ -22,4 +22,7 @@
 
 enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
 
+void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+			const char *field_name, const char *txt);
+
 #endif /* WPAS_GLUE_H */
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index e4c83b5..6af1678 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -98,5 +98,11 @@
 			ret = -1;
 	}
 
+	{
+		int crypto_module_tests(void);
+		if (crypto_module_tests() < 0)
+			ret = -1;
+	}
+
 	return ret;
 }
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 22083bd..52594a1 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -113,6 +113,7 @@
 		wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
 			   "try to associate with the received credential "
 			   "(freq=%u)", freq);
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 		if (disabled) {
@@ -160,6 +161,7 @@
 		wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
 			   "for external credential processing");
 		wpas_clear_wps(wpa_s);
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 		return 1;
@@ -913,6 +915,7 @@
 	while (ssid) {
 		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
 			if (ssid == wpa_s->current_ssid) {
+				wpa_s->own_disconnect_req = 1;
 				wpa_supplicant_deauthenticate(
 					wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 			}
@@ -1022,9 +1025,11 @@
 {
 	struct wpa_ssid *ssid;
 
-	if (wpa_s->current_ssid)
+	if (wpa_s->current_ssid) {
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(
 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	}
 
 	/* Mark all other networks disabled and trigger reassociation */
 	ssid = wpa_s->conf->ssid;
@@ -1091,6 +1096,14 @@
 		       int p2p_group)
 {
 	struct wpa_ssid *ssid;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	wpas_clear_wps(wpa_s);
 	ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
 	if (ssid == NULL)
@@ -1131,6 +1144,13 @@
 	unsigned int rpin = 0;
 	char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	wpas_clear_wps(wpa_s);
 	if (bssid && is_zero_ether_addr(bssid))
 		bssid = NULL;
@@ -1219,6 +1239,7 @@
 	} else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
 		wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
 			   "deauthenticate");
+		wpa_s->own_disconnect_req = 1;
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 		wpas_clear_wps(wpa_s);
@@ -1244,6 +1265,13 @@
 	char *pos, *end;
 	int res;
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	if (!pin)
 		return -1;
 	wpas_clear_wps(wpa_s);
@@ -1882,7 +1910,7 @@
 				    struct wps_credential *cred)
 {
 	os_memset(cred, 0, sizeof(*cred));
-	if (ssid->ssid_len > 32)
+	if (ssid->ssid_len > SSID_MAX_LEN)
 		return -1;
 	os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
 	cred->ssid_len = ssid->ssid_len;