am 79a3a004: (-s ours) am d28183c0: Merge "Android: Use external libnl 2.0 dynamic library"

* commit '79a3a004cabc2d086efc0f7af8f2b230d53b936c':
  Android: Use external libnl 2.0 dynamic library
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
new file mode 100644
index 0000000..d20a556
--- /dev/null
+++ b/CONTRIBUTIONS
@@ -0,0 +1,143 @@
+Contributions to hostap.git
+---------------------------
+
+This software is distributed under a permissive open source license to
+allow it to be used in any projects, whether open source or proprietary.
+Contributions to the project are welcome and it is important to maintain
+clear record of contributions and terms under which they are licensed.
+To help with this, following procedure is used to allow acceptance and
+recording of the terms.
+
+All contributions are expected to be licensed under the modified BSD
+license (see below). Acknowledgment of the terms is tracked through
+inclusion of Signed-off-by tag in the contributions at the end of the
+commit log message. This tag indicates that the contributor agrees with
+the Developer Certificate of Origin (DCO) version 1.1 terms (see below;
+also available from http://developercertificate.org/).
+
+
+The current requirements for contributions to hostap.git
+--------------------------------------------------------
+
+To indicate your acceptance of Developer's Certificate of Origin 1.1
+terms, please add the following line to the end of the commit message
+for each contribution you make to the project:
+
+Signed-off-by: Your Name <your@email.example.org>
+
+using your real name. Pseudonyms or anonymous contributions cannot
+unfortunately be accepted.
+
+
+History of license and contributions terms
+------------------------------------------
+
+Until February 11, 2012, in case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed both under GPL v2 and modified BSD license (see below) and
+the choice between these licenses is given to anyone who redistributes
+or uses the software. As such, the contribution has to be licensed under
+both options to allow this choice.
+
+As of February 11, 2012, the project has chosen to use only the BSD
+license option for future distribution. As such, the GPL v2 license
+option is no longer used and the contributions are not required to be
+licensed until GPL v2. In case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed under the modified BSD license (see below).
+
+Until February 13, 2014, the project used an extended version of the DCO
+that included the identical items (a) through (d) from DCO 1.1 and an
+additional item (e):
+
+(e) The contribution can be licensed under the modified BSD license
+    as shown below even in case of files that are currently licensed
+    under other terms.
+
+This was used during the period when some of the files included the old
+license terms. Acceptance of this extended DCO version was indicated
+with a Signed-hostap tag in the commit message. This additional item (e)
+was used to collect explicit approval to license the contribution with
+only the modified BSD license (see below), i.e., without the GPL v2
+option. This was done to allow simpler licensing terms to be used in the
+future. It should be noted that the modified BSD license is compatible
+with GNU GPL and as such, this possible move to simpler licensing option
+does not prevent use of this software in GPL projects.
+
+
+===[ start quote from http://developercertificate.org/ ]=======================
+
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+
+===[ end quote from http://developercertificate.org/ ]=========================
+
+
+The license terms used for hostap.git files
+-------------------------------------------
+
+Modified BSD license (no advertisement clause):
+
+Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7ecbc65..8f755e7 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -59,3 +59,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
diff --git a/README b/README
index 805c6cf..8de14a6 100644
--- a/README
+++ b/README
@@ -1,12 +1,15 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
 advertisement clause removed).
 
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
 
 This package may include either wpa_supplicant, hostapd, or both. See
 README file respective subdirectories (wpa_supplicant/README or
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 4e78c08..5d6fe56 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -45,16 +45,17 @@
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += external/openssl/include
 INCLUDES += system/security/keystore/include
 ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
 INCLUDES += external/libnl/include
+else
+INCLUDES += external/libnl-headers
+endif
 endif
 
 
@@ -108,7 +109,6 @@
 NEED_AES=y
 NEED_MD5=y
 NEED_SHA1=y
-NEED_SHA256=y
 
 OBJS += src/drivers/drivers.c
 L_CFLAGS += -DHOSTAPD
@@ -141,10 +141,10 @@
 
 
 ifndef CONFIG_NO_DUMP_STATE
-# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
-# a file (undefine it, if you want to save in binary size)
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
 L_CFLAGS += -DHOSTAPD_DUMP_STATE
-OBJS += dump_state.c
 OBJS += src/eapol_auth/eapol_auth_dump.c
 endif
 
@@ -355,7 +355,7 @@
 L_CFLAGS += -DEAP_SERVER_GPSK
 OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
 ifdef CONFIG_EAP_GPSK_SHA256
-L_CFLAGS += -DEAP_SERVER_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
 endif
 NEED_SHA256=y
 NEED_AES_OMAC1=y
@@ -531,10 +531,6 @@
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += src/crypto/crypto_gnutls.c
 HOBJS += src/crypto/crypto_gnutls.c
@@ -831,6 +827,7 @@
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
 OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_IEEE80211N
@@ -860,10 +857,20 @@
 
 OBJS += src/drivers/driver_common.c
 
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
 ifdef CONFIG_NO_STDOUT_DEBUG
 L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 L_CFLAGS += -DCONFIG_DEBUG_FILE
 endif
@@ -884,12 +891,6 @@
 OBJS_c += src/utils/edit_simple.c
 endif
 
-ifdef CONFIG_ACS
-L_CFLAGS += -DCONFIG_ACS
-OBJS += src/ap/acs.c
-LIBS += -lm
-endif
-
 ########################
 
 include $(CLEAR_VARS)
@@ -913,7 +914,11 @@
 endif
 LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl
 ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
 LOCAL_SHARED_LIBRARIES += libnl
+else
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
 endif
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_SRC_FILES := $(OBJS)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 1a4e566..5ef9676 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,8 +1,40 @@
 ChangeLog for hostapd
 
-????-??-?? - v2.1
-	* added support for simulataneous authentication of equals (SAE) for
+2014-02-04 - v2.1
+	* added support for simultaneous authentication of equals (SAE) for
 	  stronger password-based authentication with WPA2-Personal
+	* added nl80211 functionality
+	  - VHT configuration for nl80211
+	  - support split wiphy dump
+	  - driver-based MAC ACL
+	  - QoS Mapping configuration
+	* added fully automated regression testing with mac80211_hwsim
+	* allow ctrl_iface group to be specified on command line (-G<group>)
+	* allow single hostapd process to control independent WPS interfaces
+	  (wps_independent=1) instead of synchronized operations through all
+	  configured interfaces within a process
+	* avoid processing received management frames multiple times when using
+	  nl80211 with multiple BSSes
+	* added support for DFS (processing radar detection events, CAC, channel
+	  re-selection)
+	* added EAP-EKE server
+	* added automatic channel selection (ACS)
+	* added option for using per-BSS (vif) configuration files with
+	  -b<phyname>:<config file name>
+	* extended global control interface ADD/REMOVE commands to allow BSSes
+	  of a radio to be removed individually without having to add/remove all
+	  other BSSes of the radio at the same time
+	* added support for sending debug info to Linux tracing (-T on command
+	  line)
+	* replace dump_file functionality with same information being available
+	  through the hostapd control interface
+	* added support for using Protected Dual of Public Action frames for
+	  GAS/ANQP exchanges when PMF is enabled
+	* added support for WPS+NFC updates
+	  - improved protocol
+	  - option to fetch and report alternative carrier records for external
+	    NFC operations
+	* various bug fixes
 
 2013-01-12 - v2.0
 	* added AP-STA-DISCONNECTED ctrl_iface event
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fda4e4e..25c560f 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,8 +6,8 @@
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
 
 # Uncomment following line and set the path to your kernel tree include
 # directory if your C library does not include all header files.
@@ -15,6 +15,11 @@
 
 -include .config
 
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+endif
+
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
 CONFIG_OS=win32
@@ -65,6 +70,11 @@
 OBJS += ../src/drivers/drivers.o
 CFLAGS += -DHOSTAPD
 
+ifdef CONFIG_MODULE_TESTS
+CFLAGS += -DCONFIG_MODULE_TESTS
+OBJS += hapd_module_tests.o
+endif
+
 ifdef CONFIG_WPA_TRACE
 CFLAGS += -DWPA_TRACE
 OBJS += ../src/utils/trace.o
@@ -72,10 +82,10 @@
 LDFLAGS += -rdynamic
 CFLAGS += -funwind-tables
 ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DWPA_TRACE_BFD
-LIBS += -lbfd
-LIBS_c += -lbfd
-LIBS_h += -lbfd
+CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD
+LIBS += -lbfd -ldl -liberty -lz
+LIBS_c += -lbfd -ldl -liberty -lz
+LIBS_h += -lbfd -ldl -liberty -lz
 endif
 endif
 
@@ -84,6 +94,15 @@
 endif
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_h += -lrt
+LIBS_n += -lrt
+endif
+
 OBJS += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/wpa_debug.o
@@ -97,11 +116,19 @@
 OBJS += ../src/eapol_auth/eapol_auth_sm.o
 
 
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_h += -lgcov
+LIBS_n += -lgcov
+endif
+
 ifndef CONFIG_NO_DUMP_STATE
-# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
-# a file (undefine it, if you want to save in binary size)
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
 CFLAGS += -DHOSTAPD_DUMP_STATE
-OBJS += dump_state.o
 OBJS += ../src/eapol_auth/eapol_auth_dump.o
 endif
 
@@ -311,7 +338,7 @@
 CFLAGS += -DEAP_SERVER_GPSK
 OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
 ifdef CONFIG_EAP_GPSK_SHA256
-CFLAGS += -DEAP_SERVER_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
 endif
 NEED_SHA256=y
 NEED_AES_OMAC1=y
@@ -782,6 +809,7 @@
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_IEEE80211N
@@ -827,6 +855,10 @@
 CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 CFLAGS += -DCONFIG_DEBUG_FILE
 endif
@@ -837,10 +869,6 @@
 LIBS_h += -lsqlite3
 endif
 
-ifdef CONFIG_TESTING_OPTIONS
-CFLAGS += -DCONFIG_TESTING_OPTIONS
-endif
-
 ALL=hostapd hostapd_cli
 
 all: verify_config $(ALL)
@@ -852,9 +880,15 @@
 E=true
 endif
 
+ifdef CONFIG_CODE_COVERAGE
+%.o: %.c
+	@$(E) "  CC " $<
+	$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
+else
 %.o: %.c
 	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
 	@$(E) "  CC " $<
+endif
 
 verify_config:
 	@if [ ! -r .config ]; then \
@@ -923,9 +957,15 @@
 	$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
 	@$(E) "  LD " $@
 
+lcov-html:
+	lcov -c -d .. > lcov.info
+	genhtml lcov.info --output-directory lcov-html
+
 clean:
 	$(MAKE) -C ../src clean
 	rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
-	rm -f *.d
+	rm -f *.d *.gcno *.gcda *.gcov
+	rm -f lcov.info
+	rm -rf lcov-html
 
 -include $(OBJS:%.o=%.d)
diff --git a/hostapd/README b/hostapd/README
index 39b70ca..50868ee 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
 	  Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2014, 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/android.config b/hostapd/android.config
index f51a5bf..81a2e2c 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -52,7 +52,7 @@
 # This version is an experimental implementation based on IEEE 802.11w/D1.0
 # draft and is subject to change since the standard has not yet been finalized.
 # Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
 
 # Integrated EAP server
 #CONFIG_EAP=y
@@ -157,7 +157,7 @@
 # Remove support for VLANs
 #CONFIG_NO_VLAN=y
 
-# Remove support for dumping state into a file on SIGUSR1 signal
+# Remove support for dumping internal state through control interface commands
 # This can be used to reduce binary size at the cost of disabling a debugging
 # option.
 #CONFIG_NO_DUMP_STATE=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 0b4fd77..19d6ad3 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -22,9 +22,6 @@
 #include "config_file.h"
 
 
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
 #ifndef CONFIG_NO_VLAN
 static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
 					 const char *fname)
@@ -748,30 +745,32 @@
 
 static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
 {
-	struct hostapd_bss_config *bss;
+	struct hostapd_bss_config **all, *bss;
 
 	if (*ifname == '\0')
 		return -1;
 
-	bss = os_realloc_array(conf->bss, conf->num_bss + 1,
-			       sizeof(struct hostapd_bss_config));
-	if (bss == NULL) {
+	all = os_realloc_array(conf->bss, conf->num_bss + 1,
+			       sizeof(struct hostapd_bss_config *));
+	if (all == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
 			   "multi-BSS entry");
 		return -1;
 	}
-	conf->bss = bss;
+	conf->bss = all;
 
-	bss = &(conf->bss[conf->num_bss]);
-	os_memset(bss, 0, sizeof(*bss));
+	bss = os_zalloc(sizeof(*bss));
+	if (bss == NULL)
+		return -1;
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
 			   "multi-BSS RADIUS data");
+		os_free(bss);
 		return -1;
 	}
 
-	conf->num_bss++;
+	conf->bss[conf->num_bss++] = bss;
 	conf->last_bss = bss;
 
 	hostapd_config_defaults_bss(bss);
@@ -1060,15 +1059,15 @@
 	if (os_strstr(capab, "[RX-STBC-1234]"))
 		conf->vht_capab |= VHT_CAP_RXSTBC_4;
 	if (os_strstr(capab, "[SU-BEAMFORMER]"))
-		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+		conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
 	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
-		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+		conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
 	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
-	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
-		conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+		conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
 	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
-	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
-		conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+	    (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
 	if (os_strstr(capab, "[MU-BEAMFORMER]"))
 		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
 	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
@@ -1094,165 +1093,6 @@
 #endif /* CONFIG_IEEE80211AC */
 
 
-static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
-				    struct hostapd_config *conf)
-{
-	if (bss->ieee802_1x && !bss->eap_server &&
-	    !bss->radius->auth_servers) {
-		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
-			   "EAP authenticator configured).");
-		return -1;
-	}
-
-	if (bss->wpa) {
-		int wep, i;
-
-		wep = bss->default_wep_key_len > 0 ||
-		       bss->individual_wep_key_len > 0;
-		for (i = 0; i < NUM_WEP_KEYS; i++) {
-			if (bss->ssid.wep.keys_set) {
-				wep = 1;
-				break;
-			}
-		}
-
-		if (wep) {
-			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
-			return -1;
-		}
-	}
-
-	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
-	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
-		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
-			   "RADIUS checking (macaddr_acl=2) enabled.");
-		return -1;
-	}
-
-	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
-	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
-	    bss->ssid.wpa_psk_file == NULL &&
-	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
-	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
-		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
-			   "is not configured.");
-		return -1;
-	}
-
-	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
-		size_t i;
-
-		for (i = 0; i < conf->num_bss; i++) {
-			if ((&conf->bss[i] != bss) &&
-			    (hostapd_mac_comp(conf->bss[i].bssid,
-					      bss->bssid) == 0)) {
-				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
-					   " on interface '%s' and '%s'.",
-					   MAC2STR(bss->bssid),
-					   conf->bss[i].iface, bss->iface);
-				return -1;
-			}
-		}
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
-	    (bss->nas_identifier == NULL ||
-	     os_strlen(bss->nas_identifier) < 1 ||
-	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
-		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
-			   "nas_identifier to be configured as a 1..48 octet "
-			   "string");
-		return -1;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211N
-	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
-			   "allowed, disabling HT capabilites");
-	}
-
-	if (conf->ieee80211n &&
-	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
-			   "allowed, disabling HT capabilities");
-	}
-
-	if (conf->ieee80211n && bss->wpa &&
-	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
-	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
-		bss->disable_11n = 1;
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
-			   "requires CCMP/GCMP to be enabled, disabling HT "
-			   "capabilities");
-	}
-#endif /* CONFIG_IEEE80211N */
-
-#ifdef CONFIG_WPS2
-	if (bss->wps_state && bss->ignore_broadcast_ssid) {
-		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
-			   "configuration forced WPS to be disabled");
-		bss->wps_state = 0;
-	}
-
-	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
-		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
-			   "disabled");
-		bss->wps_state = 0;
-	}
-
-	if (bss->wps_state && bss->wpa &&
-	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
-		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
-			   "WPA2/CCMP forced WPS to be disabled");
-		bss->wps_state = 0;
-	}
-#endif /* CONFIG_WPS2 */
-
-#ifdef CONFIG_HS20
-	if (bss->hs20 &&
-	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
-		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
-			   "configuration is required for Hotspot 2.0 "
-			   "functionality");
-		return -1;
-	}
-#endif /* CONFIG_HS20 */
-
-	return 0;
-}
-
-
-static int hostapd_config_check(struct hostapd_config *conf)
-{
-	size_t i;
-
-	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
-		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
-			   "setting the country_code");
-		return -1;
-	}
-
-	if (conf->ieee80211h && !conf->ieee80211d) {
-		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
-			   "IEEE 802.11d enabled");
-		return -1;
-	}
-
-	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_config_check_bss(&conf->bss[i], conf))
-			return -1;
-	}
-
-	return 0;
-}
-
-
 #ifdef CONFIG_INTERWORKING
 static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
 				    int line)
@@ -1289,26 +1129,34 @@
 static int parse_lang_string(struct hostapd_lang_string **array,
 			     unsigned int *count, char *pos)
 {
-	char *sep;
-	size_t clen, nlen;
+	char *sep, *str = NULL;
+	size_t clen, nlen, slen;
 	struct hostapd_lang_string *ls;
+	int ret = -1;
+
+	if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
+		str = wpa_config_parse_string(pos, &slen);
+		if (!str)
+			return -1;
+		pos = str;
+	}
 
 	sep = os_strchr(pos, ':');
 	if (sep == NULL)
-		return -1;
+		goto fail;
 	*sep++ = '\0';
 
 	clen = os_strlen(pos);
-	if (clen < 2)
-		return -1;
+	if (clen < 2 || clen > sizeof(ls->lang))
+		goto fail;
 	nlen = os_strlen(sep);
 	if (nlen > 252)
-		return -1;
+		goto fail;
 
 	ls = os_realloc_array(*array, *count + 1,
 			      sizeof(struct hostapd_lang_string));
 	if (ls == NULL)
-		return -1;
+		goto fail;
 
 	*array = ls;
 	ls = &(*array)[*count];
@@ -1319,7 +1167,10 @@
 	ls->name_len = nlen;
 	os_memcpy(ls->name, sep, nlen);
 
-	return 0;
+	ret = 0;
+fail:
+	os_free(str);
+	return ret;
 }
 
 
@@ -1550,6 +1401,47 @@
 	return -1;
 }
 
+
+static int parse_qos_map_set(struct hostapd_bss_config *bss,
+			     char *buf, int line)
+{
+	u8 qos_map_set[16 + 2 * 21], count = 0;
+	char *pos = buf;
+	int val;
+
+	for (;;) {
+		if (count == sizeof(qos_map_set)) {
+			wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
+				   "parameters '%s'", line, buf);
+			return -1;
+		}
+
+		val = atoi(pos);
+		if (val > 255 || val < 0) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
+				   "'%s'", line, buf);
+			return -1;
+		}
+
+		qos_map_set[count++] = val;
+		pos = os_strchr(pos, ',');
+		if (!pos)
+			break;
+		pos++;
+	}
+
+	if (count < 16 || count & 1) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
+			   line, buf);
+		return -1;
+	}
+
+	os_memcpy(bss->qos_map_set, qos_map_set, count);
+	bss->qos_map_set_len = count;
+
+	return 0;
+}
+
 #endif /* CONFIG_INTERWORKING */
 
 
@@ -1700,8 +1592,8 @@
 
 	{
 		if (os_strcmp(buf, "interface") == 0) {
-			os_strlcpy(conf->bss[0].iface, pos,
-				   sizeof(conf->bss[0].iface));
+			os_strlcpy(conf->bss[0]->iface, pos,
+				   sizeof(conf->bss[0]->iface));
 		} else if (os_strcmp(buf, "bridge") == 0) {
 			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
 		} else if (os_strcmp(buf, "vlan_bridge") == 0) {
@@ -1739,7 +1631,8 @@
 		} else if (os_strcmp(buf, "logger_stdout") == 0) {
 			bss->logger_stdout = atoi(pos);
 		} else if (os_strcmp(buf, "dump_file") == 0) {
-			bss->dump_log_name = os_strdup(pos);
+			wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
+				   line);
 		} else if (os_strcmp(buf, "ssid") == 0) {
 			bss->ssid.ssid_len = os_strlen(pos);
 			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
@@ -2129,8 +2022,11 @@
 			} else {
 				os_free(bss->ssid.wpa_passphrase);
 				bss->ssid.wpa_passphrase = os_strdup(pos);
-				os_free(bss->ssid.wpa_psk);
-				bss->ssid.wpa_psk = NULL;
+				if (bss->ssid.wpa_passphrase) {
+					os_free(bss->ssid.wpa_psk);
+					bss->ssid.wpa_psk = NULL;
+					bss->ssid.wpa_passphrase_set = 1;
+				}
 			}
 		} else if (os_strcmp(buf, "wpa_psk") == 0) {
 			os_free(bss->ssid.wpa_psk);
@@ -2148,6 +2044,7 @@
 				bss->ssid.wpa_psk->group = 1;
 				os_free(bss->ssid.wpa_passphrase);
 				bss->ssid.wpa_passphrase = NULL;
+				bss->ssid.wpa_psk_set = 1;
 			}
 		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
 			os_free(bss->ssid.wpa_psk_file);
@@ -2291,6 +2188,8 @@
 			bss->radius_server_clients = os_strdup(pos);
 		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
 			bss->radius_server_auth_port = atoi(pos);
+		} else if (os_strcmp(buf, "radius_server_acct_port") == 0) {
+			bss->radius_server_acct_port = atoi(pos);
 		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
 			bss->radius_server_ipv6 = atoi(pos);
 #endif /* RADIUS_SERVER */
@@ -2523,6 +2422,8 @@
 			}
 		} else if (os_strcmp(buf, "require_ht") == 0) {
 			conf->require_ht = atoi(pos);
+		} else if (os_strcmp(buf, "obss_interval") == 0) {
+			conf->obss_interval = atoi(pos);
 #endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
@@ -2875,6 +2776,9 @@
 			bss->gas_frag_limit = atoi(pos);
 		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
 			bss->gas_comeback_delay = atoi(pos);
+		} else if (os_strcmp(buf, "qos_map_set") == 0) {
+			if (parse_qos_map_set(bss, pos, line) < 0)
+				errors++;
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_RADIUS_TEST
 		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
@@ -2947,6 +2851,25 @@
 		PARSE_TEST_PROBABILITY(ignore_assoc_probability)
 		PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
 		PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+		} else if (os_strcmp(buf, "bss_load_test") == 0) {
+			WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
+			pos = os_strchr(pos, ':');
+			if (pos == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "bss_load_test", line);
+				return 1;
+			}
+			pos++;
+			bss->bss_load_test[2] = atoi(pos);
+			pos = os_strchr(pos, ':');
+			if (pos == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "bss_load_test", line);
+				return 1;
+			}
+			pos++;
+			WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
+			bss->bss_load_test_set = 1;
 #endif /* CONFIG_TESTING_OPTIONS */
 		} else if (os_strcmp(buf, "vendor_elements") == 0) {
 			struct wpabuf *elems;
@@ -2995,53 +2918,6 @@
 }
 
 
-static void hostapd_set_security_params(struct hostapd_bss_config *bss)
-{
-	if (bss->individual_wep_key_len == 0) {
-		/* individual keys are not use; can use key idx0 for
-		 * broadcast keys */
-		bss->broadcast_key_idx_min = 0;
-	}
-
-	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
-		bss->rsn_pairwise = bss->wpa_pairwise;
-	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
-						    bss->rsn_pairwise);
-
-	bss->radius->auth_server = bss->radius->auth_servers;
-	bss->radius->acct_server = bss->radius->acct_servers;
-
-	if (bss->wpa && bss->ieee802_1x) {
-		bss->ssid.security_policy = SECURITY_WPA;
-	} else if (bss->wpa) {
-		bss->ssid.security_policy = SECURITY_WPA_PSK;
-	} else if (bss->ieee802_1x) {
-		int cipher = WPA_CIPHER_NONE;
-		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
-		bss->ssid.wep.default_len = bss->default_wep_key_len;
-		if (bss->default_wep_key_len)
-			cipher = bss->default_wep_key_len >= 13 ?
-				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
-		bss->wpa_group = cipher;
-		bss->wpa_pairwise = cipher;
-		bss->rsn_pairwise = cipher;
-	} else if (bss->ssid.wep.keys_set) {
-		int cipher = WPA_CIPHER_WEP40;
-		if (bss->ssid.wep.len[0] >= 13)
-			cipher = WPA_CIPHER_WEP104;
-		bss->ssid.security_policy = SECURITY_STATIC_WEP;
-		bss->wpa_group = cipher;
-		bss->wpa_pairwise = cipher;
-		bss->rsn_pairwise = cipher;
-	} else {
-		bss->ssid.security_policy = SECURITY_PLAINTEXT;
-		bss->wpa_group = WPA_CIPHER_NONE;
-		bss->wpa_pairwise = WPA_CIPHER_NONE;
-		bss->rsn_pairwise = WPA_CIPHER_NONE;
-	}
-}
-
-
 /**
  * hostapd_config_read - Read and parse a configuration file
  * @fname: Configuration file name (including path, if needed)
@@ -3079,7 +2955,7 @@
 		return NULL;
 	}
 
-	bss = conf->last_bss = conf->bss;
+	bss = conf->last_bss = conf->bss[0];
 
 	while (fgets(buf, sizeof(buf), f)) {
 		bss = conf->last_bss;
@@ -3113,9 +2989,9 @@
 	fclose(f);
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(&conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i]);
 
-	if (hostapd_config_check(conf))
+	if (hostapd_config_check(conf, 1))
 		errors++;
 
 #ifndef WPA_IGNORE_CONFIG_ERRORS
@@ -3145,9 +3021,9 @@
 	}
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_set_security_params(&conf->bss[i]);
+		hostapd_set_security_params(conf->bss[i]);
 
-	if (hostapd_config_check(conf)) {
+	if (hostapd_config_check(conf, 0)) {
 		wpa_printf(MSG_ERROR, "Configuration check failed");
 		return -1;
 	}
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index be941c4..7f5de62 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, 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 @@
 #include "common/ieee802_11_defs.h"
 #include "drivers/driver.h"
 #include "radius/radius_client.h"
+#include "radius/radius_server.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ieee802_1x.h"
@@ -29,6 +30,7 @@
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/wnm_ap.h"
 #include "ap/wpa_auth.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
@@ -82,15 +84,15 @@
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
 		    == 0) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
 			if (prev == NULL)
 				hapd->ctrl_dst = dst->next;
 			else
 				prev->next = dst->next;
 			os_free(dst);
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-				    (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
 			return 0;
 		}
 		prev = dst;
@@ -397,13 +399,70 @@
 static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
 						  char *cmd)
 {
-	/*
-	 * Since NFC connection handover provided full WPS Credential, there is
-	 * no need for additional operations within hostapd. Just report this in
-	 * debug log.
-	 */
-	wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
-	return 0;
+	size_t len;
+	struct wpabuf *req, *sel;
+	int ret;
+	char *pos, *role, *type, *pos2;
+
+	role = cmd;
+	pos = os_strchr(role, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	type = pos;
+	pos = os_strchr(type, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL)
+		return -1;
+	*pos2++ = '\0';
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	req = wpabuf_alloc(len);
+	if (req == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+		wpabuf_free(req);
+		return -1;
+	}
+
+	len = os_strlen(pos2);
+	if (len & 0x01) {
+		wpabuf_free(req);
+		return -1;
+	}
+	len /= 2;
+
+	sel = wpabuf_alloc(len);
+	if (sel == NULL) {
+		wpabuf_free(req);
+		return -1;
+	}
+	if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+		wpabuf_free(req);
+		wpabuf_free(sel);
+		return -1;
+	}
+
+	if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
+		ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
+	} else {
+		wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+			   "reported: role=%s type=%s", role, type);
+		ret = -1;
+	}
+	wpabuf_free(req);
+	wpabuf_free(sel);
+
+	return ret;
 }
 
 #endif /* CONFIG_WPS_NFC */
@@ -559,15 +618,114 @@
 #endif /* CONFIG_WPS */
 
 
+#ifdef CONFIG_INTERWORKING
+
+static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
+					      const char *cmd)
+{
+	u8 qos_map_set[16 + 2 * 21], count = 0;
+	const char *pos = cmd;
+	int val, ret;
+
+	for (;;) {
+		if (count == sizeof(qos_map_set)) {
+			wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
+			return -1;
+		}
+
+		val = atoi(pos);
+		if (val < 0 || val > 255) {
+			wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+			return -1;
+		}
+
+		qos_map_set[count++] = val;
+		pos = os_strchr(pos, ',');
+		if (!pos)
+			break;
+		pos++;
+	}
+
+	if (count < 16 || count & 1) {
+		wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+		return -1;
+	}
+
+	ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
+	if (ret) {
+		wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
+		return -1;
+	}
+
+	os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
+	hapd->conf->qos_map_set_len = count;
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+						const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	struct wpabuf *buf;
+	u8 *qos_map_set = hapd->conf->qos_map_set;
+	u8 qos_map_set_len = hapd->conf->qos_map_set_len;
+	int ret;
+
+	if (!qos_map_set_len) {
+		wpa_printf(MSG_INFO, "QoS Map Set is not set");
+		return -1;
+	}
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+			   "for QoS Map Configuration message",
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	if (!sta->qos_map_enabled) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
+			   "support for QoS Map", MAC2STR(addr));
+		return -1;
+	}
+
+	buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
+	if (buf == NULL)
+		return -1;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_QOS);
+	wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
+
+	/* QoS Map Set Element */
+	wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
+	wpabuf_put_u8(buf, qos_map_set_len);
+	wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
+
+	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+				      wpabuf_head(buf), wpabuf_len(buf));
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 #ifdef CONFIG_WNM
 
 static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
 						const char *cmd)
 {
 	u8 addr[ETH_ALEN];
-	u8 buf[1000], *pos;
-	struct ieee80211_mgmt *mgmt;
 	int disassoc_timer;
+	struct sta_info *sta;
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -575,31 +733,15 @@
 		return -1;
 	disassoc_timer = atoi(cmd + 17);
 
-	os_memset(buf, 0, sizeof(buf));
-	mgmt = (struct ieee80211_mgmt *) buf;
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt->da, addr, ETH_ALEN);
-	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
-	mgmt->u.action.category = WLAN_ACTION_WNM;
-	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
-	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
-	mgmt->u.action.u.bss_tm_req.req_mode =
-		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
-	mgmt->u.action.u.bss_tm_req.disassoc_timer =
-		host_to_le16(disassoc_timer);
-	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
-
-	pos = mgmt->u.action.u.bss_tm_req.variable;
-
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
-			   "Management Request frame");
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for disassociation imminent message",
+			   MAC2STR(addr));
 		return -1;
 	}
 
-	return 0;
+	return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
 }
 
 
@@ -608,14 +750,20 @@
 {
 	u8 addr[ETH_ALEN];
 	const char *url, *timerstr;
-	u8 buf[1000], *pos;
-	struct ieee80211_mgmt *mgmt;
-	size_t url_len;
 	int disassoc_timer;
+	struct sta_info *sta;
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
 
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for ESS disassociation imminent message",
+			   MAC2STR(addr));
+		return -1;
+	}
+
 	timerstr = cmd + 17;
 	if (*timerstr != ' ')
 		return -1;
@@ -628,75 +776,8 @@
 	if (url == NULL)
 		return -1;
 	url++;
-	url_len = os_strlen(url);
-	if (url_len > 255)
-		return -1;
 
-	os_memset(buf, 0, sizeof(buf));
-	mgmt = (struct ieee80211_mgmt *) buf;
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt->da, addr, ETH_ALEN);
-	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
-	mgmt->u.action.category = WLAN_ACTION_WNM;
-	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
-	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
-	mgmt->u.action.u.bss_tm_req.req_mode =
-		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
-	mgmt->u.action.u.bss_tm_req.disassoc_timer =
-		host_to_le16(disassoc_timer);
-	mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
-
-	pos = mgmt->u.action.u.bss_tm_req.variable;
-
-	/* Session Information URL */
-	*pos++ = url_len;
-	os_memcpy(pos, url, url_len);
-	pos += url_len;
-
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
-			   "Management Request frame");
-		return -1;
-	}
-
-	/* send disassociation frame after time-out */
-	if (disassoc_timer) {
-		struct sta_info *sta;
-		int timeout, beacon_int;
-
-		/*
-		 * Prevent STA from reconnecting using cached PMKSA to force
-		 * full authentication with the authentication server (which may
-		 * decide to reject the connection),
-		 */
-		wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
-
-		sta = ap_get_sta(hapd, addr);
-		if (sta == NULL) {
-			wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
-				   "for ESS disassociation imminent message",
-				   MAC2STR(addr));
-			return -1;
-		}
-
-		beacon_int = hapd->iconf->beacon_int;
-		if (beacon_int < 1)
-			beacon_int = 100; /* best guess */
-		/* Calculate timeout in ms based on beacon_int in TU */
-		timeout = disassoc_timer * beacon_int * 128 / 125;
-		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
-			   " set to %d ms", MAC2STR(addr), timeout);
-
-		sta->timeout_next = STA_DISASSOC_FROM_CLI;
-		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-		eloop_register_timeout(timeout / 1000,
-				       timeout % 1000 * 1000,
-				       ap_handle_timer, hapd, sta);
-	}
-
-	return 0;
+	return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
 }
 
 #endif /* CONFIG_WNM */
@@ -884,6 +965,10 @@
 		wps_testing_dummy_cred = atoi(value);
 		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
 			   wps_testing_dummy_cred);
+	} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+		wps_corrupt_pkhash = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+			   wps_corrupt_pkhash);
 #endif /* CONFIG_WPS_TESTING */
 #ifdef CONFIG_INTERWORKING
 	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
@@ -893,6 +978,10 @@
 		else
 			hapd->gas_frag_limit = val;
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
+		hapd->ext_mgmt_frame_handling = atoi(value);
+#endif /* CONFIG_TESTING_OPTIONS */
 	} else {
 		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
 	}
@@ -949,11 +1038,131 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+
+static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
+{
+	union wpa_event_data data;
+	char *pos, *param;
+	enum wpa_event_type event;
+
+	wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
+
+	os_memset(&data, 0, sizeof(data));
+
+	param = os_strchr(cmd, ' ');
+	if (param == NULL)
+		return -1;
+	*param++ = '\0';
+
+	if (os_strcmp(cmd, "DETECTED") == 0)
+		event = EVENT_DFS_RADAR_DETECTED;
+	else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
+		event = EVENT_DFS_CAC_FINISHED;
+	else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
+		event = EVENT_DFS_CAC_ABORTED;
+	else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
+		event = EVENT_DFS_NOP_FINISHED;
+	else {
+		wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
+			   cmd);
+		return -1;
+	}
+
+	pos = os_strstr(param, "freq=");
+	if (pos)
+		data.dfs_event.freq = atoi(pos + 5);
+
+	pos = os_strstr(param, "ht_enabled=1");
+	if (pos)
+		data.dfs_event.ht_enabled = 1;
+
+	pos = os_strstr(param, "chan_offset=");
+	if (pos)
+		data.dfs_event.chan_offset = atoi(pos + 12);
+
+	pos = os_strstr(param, "chan_width=");
+	if (pos)
+		data.dfs_event.chan_width = atoi(pos + 11);
+
+	pos = os_strstr(param, "cf1=");
+	if (pos)
+		data.dfs_event.cf1 = atoi(pos + 4);
+
+	pos = os_strstr(param, "cf2=");
+	if (pos)
+		data.dfs_event.cf2 = atoi(pos + 4);
+
+	wpa_supplicant_event(hapd, event, &data);
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
+{
+	size_t len;
+	u8 *buf;
+	int res;
+
+	wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+	len = os_strlen(cmd);
+	if (len & 1)
+		return -1;
+	len /= 2;
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (hexstr2bin(cmd, buf, len) < 0) {
+		os_free(buf);
+		return -1;
+	}
+
+	res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+	os_free(buf);
+	return res;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
+{
+#ifdef NEED_AP_MLME
+	struct csa_settings settings;
+	int ret = hostapd_parse_csa_settings(pos, &settings);
+
+	if (ret)
+		return ret;
+
+	return hostapd_switch_channel(hapd, &settings);
+#else /* NEED_AP_MLME */
+	return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
+				  int reply_size, const char *param)
+{
+#ifdef RADIUS_SERVER
+	if (os_strcmp(param, "radius_server") == 0) {
+		return radius_server_get_mib(hapd->radius_srv, reply,
+					     reply_size);
+	}
+#endif /* RADIUS_SERVER */
+	return -1;
+}
+
+
 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 				       void *sock_ctx)
 {
 	struct hostapd_data *hapd = eloop_ctx;
-	char buf[256];
+	char buf[4096];
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
@@ -989,6 +1198,11 @@
 	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
 		if (wpa_debug_reopen_file() < 0)
 			reply_len = -1;
+	} else if (os_strcmp(buf, "STATUS") == 0) {
+		reply_len = hostapd_ctrl_iface_status(hapd, reply,
+						      reply_size);
+	} else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
+		reply_len = hostapd_drv_status(hapd, reply, reply_size);
 	} else if (os_strcmp(buf, "MIB") == 0) {
 		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
 		if (reply_len >= 0) {
@@ -1018,6 +1232,9 @@
 				reply_len += res;
 		}
 #endif /* CONFIG_NO_RADIUS */
+	} else if (os_strncmp(buf, "MIB ", 4) == 0) {
+		reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
+						   buf + 4);
 	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
 		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
 							 reply_size);
@@ -1093,6 +1310,14 @@
 			reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
+		if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
+		if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
+			reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_WNM
 	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
 		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
@@ -1119,6 +1344,17 @@
 	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
 		if (hostapd_ctrl_iface_disable(hapd->iface))
 			reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
+		if (hostapd_ctrl_iface_radar(hapd, buf + 6))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+		if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
+			reply_len = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
+	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+		if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -1367,6 +1603,16 @@
 }
 
 
+static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_WPS_TESTING
+	wps_version_number = 0x20;
+	wps_testing_dummy_cred = 0;
+	wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+}
+
+
 static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
 					      void *sock_ctx)
 {
@@ -1385,6 +1631,7 @@
 		return;
 	}
 	buf[res] = '\0';
+	wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
 
 	os_memcpy(reply, "OK\n", 3);
 	reply_len = 3;
@@ -1392,12 +1639,23 @@
 	if (os_strcmp(buf, "PING") == 0) {
 		os_memcpy(reply, "PONG\n", 5);
 		reply_len = 5;
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "FLUSH") == 0) {
+		hostapd_ctrl_iface_flush(interfaces);
 	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
 		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
 			reply_len = -1;
 	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
 		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
 			reply_len = -1;
+#ifdef CONFIG_MODULE_TESTS
+	} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
+		int hapd_module_tests(void);
+		if (hapd_module_tests() < 0)
+			reply_len = -1;
+#endif /* CONFIG_MODULE_TESTS */
 	} else {
 		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
 			   "ignored");
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2dd6fc8..8c8f0ea 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -22,6 +22,19 @@
 # Driver interface for drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -42,10 +55,7 @@
 CONFIG_PEERKEY=y
 
 # IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
 
 # Integrated EAP server
 CONFIG_EAP=y
@@ -96,10 +106,9 @@
 #CONFIG_EAP_GPSK_SHA256=y
 
 # EAP-FAST for the integrated EAP server
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
-# to add the needed functions.
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
 #CONFIG_EAP_FAST=y
 
 # Wi-Fi Protected Setup (WPS)
@@ -157,6 +166,12 @@
 # Disabled by default.
 #CONFIG_DEBUG_FILE=y
 
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
 # Remove support for RADIUS accounting
 #CONFIG_NO_ACCOUNTING=y
 
@@ -174,7 +189,7 @@
 # Note: This requires libnl 3.1 or newer.
 #CONFIG_VLAN_NETLINK=y
 
-# Remove support for dumping state into a file on SIGUSR1 signal
+# Remove support for dumping internal state through control interface commands
 # This can be used to reduce binary size at the cost of disabling a debugging
 # option.
 #CONFIG_NO_DUMP_STATE=y
diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c
deleted file mode 100644
index fcd9890..0000000
--- a/hostapd/dump_state.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, 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 <time.h>
-
-#include "utils/common.h"
-#include "radius/radius_client.h"
-#include "radius/radius_server.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "eap_server/eap.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "ap/sta_info.h"
-#include "dump_state.h"
-#include "ap/ap_drv_ops.h"
-
-
-static void fprint_char(FILE *f, char c)
-{
-	if (c >= 32 && c < 127)
-		fprintf(f, "%c", c);
-	else
-		fprintf(f, "<%02x>", c);
-}
-
-
-static void ieee802_1x_dump_state(FILE *f, const char *prefix,
-				  struct sta_info *sta)
-{
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	if (sm == NULL)
-		return;
-
-	fprintf(f, "%sIEEE 802.1X:\n", prefix);
-
-	if (sm->identity) {
-		size_t i;
-		fprintf(f, "%sidentity=", prefix);
-		for (i = 0; i < sm->identity_len; i++)
-			fprint_char(f, sm->identity[i]);
-		fprintf(f, "\n");
-	}
-
-	fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
-		"Supplicant: %d (%s)\n", prefix,
-		sm->eap_type_authsrv,
-		eap_server_get_name(0, sm->eap_type_authsrv),
-		sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
-
-	fprintf(f, "%scached_packets=%s\n", prefix,
-		sm->last_recv_radius ? "[RX RADIUS]" : "");
-
-	eapol_auth_dump_state(f, prefix, sm);
-}
-
-
-/**
- * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
- */
-static void hostapd_dump_state(struct hostapd_data *hapd)
-{
-	FILE *f;
-	time_t now;
-	struct sta_info *sta;
-	int i;
-#ifndef CONFIG_NO_RADIUS
-	char *buf;
-#endif /* CONFIG_NO_RADIUS */
-	struct hostap_sta_driver_data data;
-
-	if (!hapd->conf->dump_log_name) {
-		wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
-			   "request");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
-		   hapd->conf->dump_log_name);
-	f = fopen(hapd->conf->dump_log_name, "w");
-	if (f == NULL) {
-		wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
-			   "writing.", hapd->conf->dump_log_name);
-		return;
-	}
-
-	time(&now);
-	fprintf(f, "hostapd state dump - %s", ctime(&now));
-	fprintf(f, "num_sta=%d num_sta_non_erp=%d "
-		"num_sta_no_short_slot_time=%d\n"
-		"num_sta_no_short_preamble=%d\n",
-		hapd->num_sta, hapd->iface->num_sta_non_erp,
-		hapd->iface->num_sta_no_short_slot_time,
-		hapd->iface->num_sta_no_short_preamble);
-
-	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
-		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
-
-		fprintf(f,
-			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
-			"\n"
-			"  capability=0x%x listen_interval=%d\n",
-			sta->aid,
-			sta->flags,
-			(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
-			(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
-			(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
-			(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
-			(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
-			(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
-			(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
-			 ""),
-			(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
-			 "[SHORT_PREAMBLE]" : ""),
-			(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
-			(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
-			(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
-			(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
-			(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
-			(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
-			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
-			(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
-			sta->capability,
-			sta->listen_interval);
-
-		fprintf(f, "  supported_rates=");
-		for (i = 0; i < sta->supported_rates_len; i++)
-			fprintf(f, "%02x ", sta->supported_rates[i]);
-		fprintf(f, "\n");
-
-		fprintf(f,
-			"  timeout_next=%s\n",
-			(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
-			 (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
-			  "DEAUTH")));
-
-		ieee802_1x_dump_state(f, "  ", sta);
-
-		if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) == 0) {
-			fprintf(f, "  rx_pkt=%lu tx_pkt=%lu\n"
-				"  rx_byte=%lu tx_byte=%lu\n",
-				data.rx_packets, data.tx_packets,
-				data.rx_bytes, data.tx_bytes);
-		}
-	}
-
-#ifndef CONFIG_NO_RADIUS
-	buf = os_malloc(4096);
-	if (buf) {
-		int count = radius_client_get_mib(hapd->radius, buf, 4096);
-		if (count < 0)
-			count = 0;
-		else if (count > 4095)
-			count = 4095;
-		buf[count] = '\0';
-		fprintf(f, "%s", buf);
-
-#ifdef RADIUS_SERVER
-		count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
-		if (count < 0)
-			count = 0;
-		else if (count > 4095)
-			count = 4095;
-		buf[count] = '\0';
-		fprintf(f, "%s", buf);
-#endif /* RADIUS_SERVER */
-
-		os_free(buf);
-	}
-#endif /* CONFIG_NO_RADIUS */
-	fclose(f);
-}
-
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
-{
-	size_t i;
-
-	for (i = 0; i < iface->num_bss; i++)
-		hostapd_dump_state(iface->bss[i]);
-
-	return 0;
-}
diff --git a/hostapd/dump_state.h b/hostapd/dump_state.h
deleted file mode 100644
index a209d65..0000000
--- a/hostapd/dump_state.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef DUMP_STATE_H
-#define DUMP_STATE_H
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
-
-#endif /* DUMP_STATE_H */
diff --git a/hostapd/hapd_module_tests.c b/hostapd/hapd_module_tests.c
new file mode 100644
index 0000000..f7887eb
--- /dev/null
+++ b/hostapd/hapd_module_tests.c
@@ -0,0 +1,17 @@
+/*
+ * hostapd module tests
+ * Copyright (c) 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"
+
+int hapd_module_tests(void)
+{
+	wpa_printf(MSG_INFO, "hostapd module tests");
+	return 0;
+}
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index e04e2e9..c041887 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2013, 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,9 @@
  * SIM-REQ-AUTH <IMSI> <max_chal>
  * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
  * SIM-RESP-AUTH <IMSI> FAILURE
+ * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
+ * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
+ * GSM-AUTH-RESP <IMSI> FAILURE
  *
  * EAP-AKA / UMTS query/response:
  * AKA-REQ-AUTH <IMSI>
@@ -30,12 +33,16 @@
  * IMSI and max_chal are sent as an ASCII string,
  * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
  *
- * The example implementation here reads GSM authentication triplets from a
+ * An example implementation here reads GSM authentication triplets from a
  * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
  * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
  * for real life authentication, but it is useful both as an example
  * implementation and for EAP-SIM/AKA/AKA' testing.
  *
+ * For a stronger example design, Milenage and GSM-Milenage algorithms can be
+ * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
+ * EAP-SIM, respectively, if Ki is known.
+ *
  * SQN generation follows the not time-based Profile 2 described in
  * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
  * can be changed with a command line options if needed.
@@ -58,6 +65,7 @@
 static int update_milenage = 0;
 static int sqn_changes = 0;
 static int ind_len = 5;
+static int stdout_debug = 1;
 
 /* GSM triplets */
 struct gsm_triplet {
@@ -214,6 +222,9 @@
 {
 	char cmd[128], val[13], *pos;
 
+	if (sqlite_db == NULL)
+		return 0;
+
 	pos = val;
 	pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
 	*pos = '\0';
@@ -611,31 +622,30 @@
 }
 
 
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
+static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
 {
 	int count, max_chal, ret;
 	char *pos;
-	char reply[1000], *rpos, *rend;
+	char *rpos, *rend;
 	struct milenage_parameters *m;
 	struct gsm_triplet *g;
 
-	reply[0] = '\0';
+	resp[0] = '\0';
 
 	pos = strchr(imsi, ' ');
 	if (pos) {
 		*pos++ = '\0';
 		max_chal = atoi(pos);
-		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+		if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
 			max_chal = EAP_SIM_MAX_CHAL;
 	} else
 		max_chal = EAP_SIM_MAX_CHAL;
 
-	rend = &reply[sizeof(reply)];
-	rpos = reply;
+	rend = resp + resp_len;
+	rpos = resp;
 	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
 	if (ret < 0 || ret >= rend - rpos)
-		return;
+		return -1;
 	rpos += ret;
 
 	m = get_milenage(imsi);
@@ -643,7 +653,7 @@
 		u8 _rand[16], sres[4], kc[8];
 		for (count = 0; count < max_chal; count++) {
 			if (random_get_bytes(_rand, 16) < 0)
-				return;
+				return -1;
 			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
 			*rpos++ = ' ';
 			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
@@ -653,7 +663,7 @@
 			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
 		}
 		*rpos = '\0';
-		goto send;
+		return 0;
 	}
 
 	count = 0;
@@ -677,15 +687,61 @@
 		printf("No GSM triplets found for %s\n", imsi);
 		ret = snprintf(rpos, rend - rpos, " FAILURE");
 		if (ret < 0 || ret >= rend - rpos)
-			return;
+			return -1;
 		rpos += ret;
 	}
 
-send:
-	printf("Send: %s\n", reply);
-	if (sendto(s, reply, rpos - reply, 0,
-		   (struct sockaddr *) from, fromlen) < 0)
-		perror("send");
+	return 0;
+}
+
+
+static int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
+{
+	int count, ret;
+	char *pos, *rpos, *rend;
+	struct milenage_parameters *m;
+
+	resp[0] = '\0';
+
+	pos = os_strchr(imsi, ' ');
+	if (!pos)
+		return -1;
+	*pos++ = '\0';
+
+	rend = resp + resp_len;
+	rpos = resp;
+	ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
+	if (ret < 0 || ret >= rend - rpos)
+		return -1;
+	rpos += ret;
+
+	m = get_milenage(imsi);
+	if (m) {
+		u8 _rand[16], sres[4], kc[8];
+		for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
+			if (hexstr2bin(pos, _rand, 16) != 0)
+				return -1;
+			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+			*rpos++ = count == 0 ? ' ' : ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+			pos += 16 * 2;
+			if (*pos != ':')
+				break;
+			pos++;
+		}
+		*rpos = '\0';
+		return 0;
+	}
+
+	printf("No GSM triplets found for %s\n", imsi);
+	ret = os_snprintf(rpos, rend - rpos, " FAILURE");
+	if (ret < 0 || ret >= rend - rpos)
+		return -1;
+	rpos += ret;
+
+	return 0;
 }
 
 
@@ -711,11 +767,10 @@
 }
 
 
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
+static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
 {
 	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
-	char reply[1000], *pos, *end;
+	char *pos, *end;
 	u8 _rand[EAP_AKA_RAND_LEN];
 	u8 autn[EAP_AKA_AUTN_LEN];
 	u8 ik[EAP_AKA_IK_LEN];
@@ -729,16 +784,18 @@
 	m = get_milenage(imsi);
 	if (m) {
 		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
-			return;
+			return -1;
 		res_len = EAP_AKA_RES_MAX_LEN;
 		inc_sqn(m->sqn);
 #ifdef CONFIG_SQLITE
 		db_update_milenage_sqn(m);
 #endif /* CONFIG_SQLITE */
 		sqn_changes = 1;
-		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
-		       m->sqn[0], m->sqn[1], m->sqn[2],
-		       m->sqn[3], m->sqn[4], m->sqn[5]);
+		if (stdout_debug) {
+			printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+			       m->sqn[0], m->sqn[1], m->sqn[2],
+			       m->sqn[3], m->sqn[4], m->sqn[5]);
+		}
 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
 				  autn, ik, ck, res, &res_len);
 	} else {
@@ -756,18 +813,18 @@
 #endif /* AKA_USE_FIXED_TEST_VALUES */
 	}
 
-	pos = reply;
-	end = &reply[sizeof(reply)];
+	pos = resp;
+	end = resp + resp_len;
 	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
 	if (ret < 0 || ret >= end - pos)
-		return;
+		return -1;
 	pos += ret;
 	if (failed) {
 		ret = snprintf(pos, end - pos, "FAILURE");
 		if (ret < 0 || ret >= end - pos)
-			return;
+			return -1;
 		pos += ret;
-		goto done;
+		return 0;
 	}
 	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
 	*pos++ = ' ';
@@ -779,65 +836,87 @@
 	*pos++ = ' ';
 	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
 
-done:
-	printf("Send: %s\n", reply);
-
-	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
-		   fromlen) < 0)
-		perror("send");
+	return 0;
 }
 
 
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
-		     char *imsi)
+static int aka_auts(char *imsi, char *resp, size_t resp_len)
 {
 	char *auts, *__rand;
 	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
 	struct milenage_parameters *m;
 
+	resp[0] = '\0';
+
 	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
 
 	auts = strchr(imsi, ' ');
 	if (auts == NULL)
-		return;
+		return -1;
 	*auts++ = '\0';
 
 	__rand = strchr(auts, ' ');
 	if (__rand == NULL)
-		return;
+		return -1;
 	*__rand++ = '\0';
 
-	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+	if (stdout_debug) {
+		printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
+		       imsi, auts, __rand);
+	}
 	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
 	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
 		printf("Could not parse AUTS/RAND\n");
-		return;
+		return -1;
 	}
 
 	m = get_milenage(imsi);
 	if (m == NULL) {
 		printf("Unknown IMSI: %s\n", imsi);
-		return;
+		return -1;
 	}
 
 	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
 		printf("AKA-AUTS: Incorrect MAC-S\n");
 	} else {
 		memcpy(m->sqn, sqn, 6);
-		printf("AKA-AUTS: Re-synchronized: "
-		       "SQN=%02x%02x%02x%02x%02x%02x\n",
-		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+		if (stdout_debug) {
+			printf("AKA-AUTS: Re-synchronized: "
+			       "SQN=%02x%02x%02x%02x%02x%02x\n",
+			       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+		}
 #ifdef CONFIG_SQLITE
 		db_update_milenage_sqn(m);
 #endif /* CONFIG_SQLITE */
 		sqn_changes = 1;
 	}
+
+	return 0;
+}
+
+
+static int process_cmd(char *cmd, char *resp, size_t resp_len)
+{
+	if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
+		return sim_req_auth(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
+		return gsm_auth_req(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
+		return aka_req_auth(cmd + 13, resp, resp_len);
+
+	if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
+		return aka_auts(cmd + 9, resp, resp_len);
+
+	printf("Unknown request: %s\n", cmd);
+	return -1;
 }
 
 
 static int process(int s)
 {
-	char buf[1000];
+	char buf[1000], resp[1000];
 	struct sockaddr_un from;
 	socklen_t fromlen;
 	ssize_t res;
@@ -859,14 +938,21 @@
 
 	printf("Received: %s\n", buf);
 
-	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
-		sim_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
-		aka_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
-		aka_auts(s, &from, fromlen, buf + 9);
-	else
-		printf("Unknown request: %s\n", buf);
+	if (process_cmd(buf, resp, sizeof(resp)) < 0) {
+		printf("Failed to process request\n");
+		return -1;
+	}
+
+	if (resp[0] == '\0') {
+		printf("No response\n");
+		return 0;
+	}
+
+	printf("Send: %s\n", resp);
+
+	if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
+		   fromlen) < 0)
+		perror("send");
 
 	return 0;
 }
@@ -894,8 +980,10 @@
 		os_free(prev);
 	}
 
-	close(serv_sock);
-	unlink(socket_path);
+	if (serv_sock >= 0)
+		close(serv_sock);
+	if (socket_path)
+		unlink(socket_path);
 
 #ifdef CONFIG_SQLITE
 	if (sqlite_db) {
@@ -917,12 +1005,12 @@
 {
 	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
 	       "database/authenticator\n"
-	       "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
+	       "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
 	       "\n"
 	       "usage:\n"
 	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
 	       "[-m<milenage file>] \\\n"
-	       "        [-D<DB file>] [-i<IND len in bits>]\n"
+	       "        [-D<DB file>] [-i<IND len in bits>] [command]\n"
 	       "\n"
 	       "options:\n"
 	       "  -h = show this usage help\n"
@@ -932,7 +1020,15 @@
 	       "  -g<triplet file> = path for GSM authentication triplets\n"
 	       "  -m<milenage file> = path for Milenage keys\n"
 	       "  -D<DB file> = path to SQLite database\n"
-	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
+	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n"
+	       "\n"
+	       "If the optional command argument, like "
+	       "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
+	       "command is processed with response sent to stdout. Otherwise, "
+	       "hlr_auc_gw opens\n"
+	       "a control interface and processes commands sent through it "
+	       "(e.g., by EAP server\n"
+	       "in hostapd).\n",
 	       default_socket_path);
 }
 
@@ -942,6 +1038,7 @@
 	int c;
 	char *gsm_triplet_file = NULL;
 	char *sqlite_db_file = NULL;
+	int ret = 0;
 
 	if (os_program_init())
 		return -1;
@@ -1005,18 +1102,31 @@
 	if (milenage_file && read_milenage(milenage_file) < 0)
 		return -1;
 
-	serv_sock = open_socket(socket_path);
-	if (serv_sock < 0)
-		return -1;
+	if (optind == argc) {
+		serv_sock = open_socket(socket_path);
+		if (serv_sock < 0)
+			return -1;
 
-	printf("Listening for requests on %s\n", socket_path);
+		printf("Listening for requests on %s\n", socket_path);
 
-	atexit(cleanup);
-	signal(SIGTERM, handle_term);
-	signal(SIGINT, handle_term);
+		atexit(cleanup);
+		signal(SIGTERM, handle_term);
+		signal(SIGINT, handle_term);
 
-	for (;;)
-		process(serv_sock);
+		for (;;)
+			process(serv_sock);
+	} else {
+		char buf[1000];
+		socket_path = NULL;
+		stdout_debug = 0;
+		if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
+			printf("FAIL\n");
+			ret = -1;
+		} else {
+			printf("%s\n", buf);
+		}
+		cleanup();
+	}
 
 #ifdef CONFIG_SQLITE
 	if (sqlite_db) {
@@ -1027,5 +1137,5 @@
 
 	os_program_deinit();
 
-	return 0;
+	return ret;
 }
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 45897ed..c503ce2 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -51,9 +51,6 @@
 logger_stdout=-1
 logger_stdout_level=2
 
-# Dump file for state information (on SIGUSR1)
-dump_file=/tmp/hostapd.dump
-
 # Interface for separate control program. If this is specified, hostapd
 # will create this directory and a UNIX domain socket for listening to requests
 # from external programs (CLI/GUI, etc.) for status information and
@@ -416,6 +413,12 @@
 # associated stations in the BSS. By default, this bridging is allowed.
 #ap_isolate=1
 
+# Fixed BSS Load value for testing purposes
+# This field can be used to configure hostapd to add a fixed BSS Load element
+# into Beacon and Probe Response frames for testing purposes. The format is
+# <station count>:<channel utilization>:<available admission capacity>
+#bss_load_test=12:80:20000
+
 ##### IEEE 802.11n related configuration ######################################
 
 # ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -462,6 +465,13 @@
 # Require stations to support HT PHY (reject association if they do not)
 #require_ht=1
 
+# 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.
+#obss_interval=0
+
 ##### IEEE 802.11ac related configuration #####################################
 
 # ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
@@ -961,6 +971,11 @@
 # The UDP port number for the RADIUS authentication server
 #radius_server_auth_port=1812
 
+# The UDP port number for the RADIUS accounting server
+# Commenting this out or setting this to 0 can be used to disable RADIUS
+# accounting while still enabling RADIUS authentication.
+#radius_server_acct_port=1813
+
 # Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
 #radius_server_ipv6=1
 
@@ -1457,6 +1472,9 @@
 # information to be complete.
 #venue_name=eng:Example venue
 #venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
 
 # Network Authentication Type
 # This parameter indicates what type of network authentication is used in the
@@ -1521,6 +1539,23 @@
 # username/password
 #nai_realm=0,example.org,13[5:6],21[2:4][5:7]
 
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
 ##### Hotspot 2.0 #############################################################
 
 # Enable Hotspot 2.0 support
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 7187abc..eee8504 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,7 +18,7 @@
 
 static const char *hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *hostapd_cli_license =
@@ -216,8 +216,21 @@
 }
 
 
+static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
+	return wpa_ctrl_command(ctrl, "STATUS");
+}
+
+
 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
+	if (argc > 0) {
+		char buf[100];
+		os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
+		return wpa_ctrl_command(ctrl, buf);
+	}
 	return wpa_ctrl_command(ctrl, "MIB");
 }
 
@@ -270,12 +283,15 @@
 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char buf[64];
-	if (argc != 1) {
-		printf("Invalid 'sta' command - exactly one argument, STA "
+	if (argc < 1) {
+		printf("Invalid 'sta' command - at least one argument, STA "
 		       "address, is required.\n");
 		return -1;
 	}
-	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+	if (argc > 1)
+		snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
+	else
+		snprintf(buf, sizeof(buf), "STA %s", argv[0]);
 	return wpa_ctrl_command(ctrl, buf);
 }
 
@@ -688,6 +704,45 @@
 }
 
 
+static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
+					   int argc, char *argv[])
+{
+	char buf[200];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'set_qos_map_set' command - "
+		       "one argument (comma delimited QoS map set) "
+		       "is needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
+					     int argc, char *argv[])
+{
+	char buf[50];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'send_qos_map_conf' command - "
+		       "one argument (STA addr) is needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	hostapd_cli_quit = 1;
@@ -801,6 +856,45 @@
 }
 
 
+static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
+				       int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+	int i;
+	char *tmp;
+	int total;
+
+	if (argc < 2) {
+		printf("Invalid chan_switch command: needs at least two "
+		       "arguments (count and freq)\n"
+		       "usage: <cs_count> <freq> [sec_channel_offset=] "
+		       "[center_freq1=] [center_freq2=] [bandwidth=] "
+		       "[blocktx] [ht|vht]\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long CHAN_SWITCH command.\n");
+		return -1;
+	}
+
+	total = res;
+	for (i = 2; i < argc; i++) {
+		tmp = cmd + total;
+		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
+		if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+			printf("Too long CHAN_SWITCH command.\n");
+			return -1;
+		}
+		total += res;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 struct hostapd_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -810,6 +904,7 @@
 	{ "ping", hostapd_cli_cmd_ping },
 	{ "mib", hostapd_cli_cmd_mib },
 	{ "relog", hostapd_cli_cmd_relog },
+	{ "status", hostapd_cli_cmd_status },
 	{ "sta", hostapd_cli_cmd_sta },
 	{ "all_sta", hostapd_cli_cmd_all_sta },
 	{ "new_sta", hostapd_cli_cmd_new_sta },
@@ -843,6 +938,9 @@
 	{ "quit", hostapd_cli_cmd_quit },
 	{ "set", hostapd_cli_cmd_set },
 	{ "get", hostapd_cli_cmd_get },
+	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
+	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
+	{ "chan_switch", hostapd_cli_cmd_chan_switch },
 	{ NULL, NULL }
 };
 
diff --git a/hostapd/main.c b/hostapd/main.c
index 90e5966..3026929 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -14,6 +14,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/uuid.h"
 #include "crypto/random.h"
 #include "crypto/tls.h"
 #include "common/version.h"
@@ -25,17 +26,9 @@
 #include "ap/ap_drv_ops.h"
 #include "config_file.h"
 #include "eap_register.h"
-#include "dump_state.h"
 #include "ctrl_iface.h"
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
 struct hapd_global {
 	void **drv_priv;
 	size_t drv_count;
@@ -99,7 +92,8 @@
 	if (hapd && hapd->conf && addr)
 		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
 			    hapd->conf->iface, MAC2STR(addr),
-			    module_str ? " " : "", module_str, txt);
+			    module_str ? " " : "", module_str ? module_str : "",
+			    txt);
 	else if (hapd && hapd->conf)
 		os_snprintf(format, maxlen, "%s:%s%s %s",
 			    hapd->conf->iface, module_str ? " " : "",
@@ -114,7 +108,7 @@
 
 	if ((conf_stdout & module) && level >= conf_stdout_level) {
 		wpa_debug_print_timestamp();
-		printf("%s\n", format);
+		wpa_printf(MSG_INFO, "%s", format);
 	}
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -148,65 +142,8 @@
 
 
 /**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
  */
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
-	struct hostapd_iface *hapd_iface = NULL;
-	struct hostapd_config *conf = NULL;
-	struct hostapd_data *hapd;
-	size_t i;
-
-	hapd_iface = os_zalloc(sizeof(*hapd_iface));
-	if (hapd_iface == NULL)
-		goto fail;
-
-	hapd_iface->config_fname = os_strdup(config_file);
-	if (hapd_iface->config_fname == NULL)
-		goto fail;
-
-	conf = hostapd_config_read(hapd_iface->config_fname);
-	if (conf == NULL)
-		goto fail;
-	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)
-		goto fail;
-
-	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)
-			goto fail;
-		hapd->msg_ctx = hapd;
-	}
-
-	return hapd_iface;
-
-fail:
-	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
-		   config_file);
-	if (conf)
-		hostapd_config_free(conf);
-	if (hapd_iface) {
-		os_free(hapd_iface->config_fname);
-		os_free(hapd_iface->bss);
-		os_free(hapd_iface);
-	}
-	return NULL;
-}
-
-
 static int hostapd_driver_init(struct hostapd_iface *iface)
 {
 	struct wpa_init_params params;
@@ -286,6 +223,13 @@
 }
 
 
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
 static struct hostapd_iface *
 hostapd_interface_init(struct hapd_interfaces *interfaces,
 		       const char *config_fname, int debug)
@@ -294,7 +238,7 @@
 	int k;
 
 	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
-	iface = hostapd_init(config_fname);
+	iface = hostapd_init(interfaces, config_fname);
 	if (!iface)
 		return NULL;
 	iface->interfaces = interfaces;
@@ -304,7 +248,7 @@
 			iface->bss[0]->conf->logger_stdout_level--;
 	}
 
-	if (iface->conf->bss[0].iface[0] == '\0' &&
+	if (iface->conf->bss[0]->iface[0] == '\0' &&
 	    !hostapd_drv_none(iface->bss[0])) {
 		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
 			   config_fname);
@@ -312,12 +256,6 @@
 		return NULL;
 	}
 
-	if (hostapd_driver_init(iface) ||
-	    hostapd_setup_interface(iface)) {
-		hostapd_interface_deinit_free(iface);
-		return NULL;
-	}
-
 	return iface;
 }
 
@@ -358,10 +296,7 @@
 
 static void handle_dump_state(int sig, void *signal_ctx)
 {
-#ifdef HOSTAPD_DUMP_STATE
-	struct hapd_interfaces *interfaces = signal_ctx;
-	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
-#endif /* HOSTAPD_DUMP_STATE */
+	/* Not used anymore - ignore signal */
 }
 #endif /* CONFIG_NATIVE_WINDOWS */
 
@@ -480,7 +415,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-2013, Jouni Malinen <j@w1.fi> "
+		"Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> "
 		"and contributors\n");
 }
 
@@ -507,6 +442,10 @@
 #ifdef CONFIG_DEBUG_FILE
 		"   -f   log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		"   -T = record to Linux tracing in addition to logging\n"
+		"        (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		"   -t   include timestamps in some debug messages\n"
 		"   -v   show hostapd version\n");
 
@@ -517,8 +456,9 @@
 static const char * hostapd_msg_ifname_cb(void *ctx)
 {
 	struct hostapd_data *hapd = ctx;
-	if (hapd && hapd->iconf && hapd->iconf->bss)
-		return hapd->iconf->bss->iface;
+	if (hapd && hapd->iconf && hapd->iconf->bss &&
+	    hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+		return hapd->iconf->bss[0]->iface;
 	return NULL;
 }
 
@@ -563,15 +503,41 @@
 }
 
 
+#ifdef CONFIG_WPS
+static int gen_uuid(const char *txt_addr)
+{
+	u8 addr[ETH_ALEN];
+	u8 uuid[UUID_LEN];
+	char buf[100];
+
+	if (hwaddr_aton(txt_addr, addr) < 0)
+		return -1;
+
+	uuid_gen_mac_addr(addr, uuid);
+	if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
+		return -1;
+
+	printf("%s\n", buf);
+
+	return 0;
+}
+#endif /* CONFIG_WPS */
+
+
 int main(int argc, char *argv[])
 {
 	struct hapd_interfaces interfaces;
 	int ret = 1;
-	size_t i;
+	size_t i, j;
 	int c, debug = 0, daemonize = 0;
 	char *pid_file = NULL;
 	const char *log_file = NULL;
 	const char *entropy_file = NULL;
+	char **bss_config = NULL, **tmp_bss;
+	size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	if (os_program_init())
 		return -1;
@@ -588,7 +554,7 @@
 	interfaces.global_ctrl_sock = -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
+		c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -619,6 +585,11 @@
 		case 't':
 			wpa_debug_timestamp++;
 			break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		case 'T':
+			enable_trace_dbg = 1;
+			break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		case 'v':
 			show_version();
 			exit(1);
@@ -631,23 +602,46 @@
 			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
 				return -1;
 			break;
+		case 'b':
+			tmp_bss = os_realloc_array(bss_config,
+						   num_bss_configs + 1,
+						   sizeof(char *));
+			if (tmp_bss == NULL)
+				goto out;
+			bss_config = tmp_bss;
+			bss_config[num_bss_configs++] = optarg;
+			break;
+#ifdef CONFIG_WPS
+		case 'u':
+			return gen_uuid(optarg);
+#endif /* CONFIG_WPS */
 		default:
 			usage();
 			break;
 		}
 	}
 
-	if (optind == argc && interfaces.global_iface_path == NULL)
+	if (optind == argc && interfaces.global_iface_path == NULL &&
+	    num_bss_configs == 0)
 		usage();
 
 	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
 
 	if (log_file)
 		wpa_debug_open_file(log_file);
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (enable_trace_dbg) {
+		int tret = wpa_debug_open_linux_tracing();
+		if (tret) {
+			wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+			return -1;
+		}
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	interfaces.count = argc - optind;
-	if (interfaces.count) {
-		interfaces.iface = os_calloc(interfaces.count,
+	if (interfaces.count || num_bss_configs) {
+		interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
 					     sizeof(struct hostapd_iface *));
 		if (interfaces.iface == NULL) {
 			wpa_printf(MSG_ERROR, "malloc failed");
@@ -660,7 +654,7 @@
 		return -1;
 	}
 
-	/* Initialize interfaces */
+	/* Allocate and parse configuration for full interface files */
 	for (i = 0; i < interfaces.count; i++) {
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
 							     argv[optind + i],
@@ -671,6 +665,57 @@
 		}
 	}
 
+	/* Allocate and parse configuration for per-BSS files */
+	for (i = 0; i < num_bss_configs; i++) {
+		struct hostapd_iface *iface;
+		char *fname;
+
+		wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+		fname = os_strchr(bss_config[i], ':');
+		if (fname == NULL) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid BSS config identifier '%s'",
+				   bss_config[i]);
+			goto out;
+		}
+		*fname++ = '\0';
+		iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+						   fname, debug);
+		if (iface == NULL)
+			goto out;
+		for (j = 0; j < interfaces.count; j++) {
+			if (interfaces.iface[j] == iface)
+				break;
+		}
+		if (j == interfaces.count) {
+			struct hostapd_iface **tmp;
+			tmp = os_realloc_array(interfaces.iface,
+					       interfaces.count + 1,
+					       sizeof(struct hostapd_iface *));
+			if (tmp == NULL) {
+				hostapd_interface_deinit_free(iface);
+				goto out;
+			}
+			interfaces.iface = tmp;
+			interfaces.iface[interfaces.count++] = iface;
+		}
+	}
+
+	/*
+	 * Enable configured interfaces. Depending on channel configuration,
+	 * this may complete full initialization before returning or use a
+	 * callback mechanism to complete setup in case of operations like HT
+	 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+	 * In such case, the interface will be enabled from eloop context within
+	 * hostapd_global_run().
+	 */
+	interfaces.terminate_on_error = interfaces.count;
+	for (i = 0; i < interfaces.count; i++) {
+		if (hostapd_driver_init(interfaces.iface[i]) ||
+		    hostapd_setup_interface(interfaces.iface[i]))
+			goto out;
+	}
+
 	hostapd_global_ctrl_iface_init(&interfaces);
 
 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
@@ -692,6 +737,9 @@
 
 	if (log_file)
 		wpa_debug_close_file();
+	wpa_debug_close_linux_tracing();
+
+	os_free(bss_config);
 
 	os_program_deinit();
 
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
index 61b5519..2fc3012 100755
--- a/hostapd/wps-ap-nfc.py
+++ b/hostapd/wps-ap-nfc.py
@@ -9,6 +9,7 @@
 import os
 import sys
 import time
+import argparse
 
 import nfc
 import nfc.ndef
@@ -16,11 +17,25 @@
 import nfc.handover
 
 import logging
-logging.basicConfig()
 
 import wpaspy
 
 wpas_ctrl = '/var/run/hostapd'
+continue_loop = True
+summary_file = None
+success_file = None
+
+def summary(txt):
+    print txt
+    if summary_file:
+        with open(summary_file, 'a') as f:
+            f.write(txt + "\n")
+
+def success_report(txt):
+    summary(txt)
+    if success_file:
+        with open(success_file, 'a') as f:
+            f.write(txt + "\n")
 
 def wpas_connect():
     ifaces = []
@@ -47,29 +62,40 @@
 def wpas_tag_read(message):
     wpas = wpas_connect()
     if (wpas == None):
-        return
-    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+        return False
+    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+        return False
+    return True
 
 
 def wpas_get_config_token():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+    ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_get_password_token():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+    ret = wpas.request("WPS_NFC_TOKEN NDEF")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_get_handover_sel():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+    ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_report_handover(req, sel):
@@ -82,185 +108,228 @@
 
 
 class HandoverServer(nfc.handover.HandoverServer):
-    def __init__(self):
-        super(HandoverServer, self).__init__()
+    def __init__(self, llc):
+        super(HandoverServer, self).__init__(llc)
+        self.ho_server_processing = False
+        self.success = False
+
+    # override to avoid parser error in request/response.pretty() in nfcpy
+    # due to new WSC handover format
+    def _process_request(self, request):
+        summary("received handover request {}".format(request.type))
+        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+        if not request.type == 'urn:nfc:wkt:Hr':
+            summary("not a handover request")
+        else:
+            try:
+                request = nfc.ndef.HandoverRequestMessage(request)
+            except nfc.ndef.DecodeError as e:
+                summary("error decoding 'Hr' message: {}".format(e))
+            else:
+                response = self.process_request(request)
+        summary("send handover response {}".format(response.type))
+        return response
 
     def process_request(self, request):
-        print "HandoverServer - request received"
-        print "Parsed handover request: " + request.pretty()
+        summary("HandoverServer - request received")
+        try:
+            print "Parsed handover request: " + request.pretty()
+        except Exception, e:
+            print e
+        print str(request).encode("hex")
 
         sel = nfc.ndef.HandoverSelectMessage(version="1.2")
 
         for carrier in request.carriers:
             print "Remote carrier type: " + carrier.type
             if carrier.type == "application/vnd.wfa.wsc":
-                print "WPS carrier type match - add WPS carrier record"
-                self.received_carrier = carrier.record
+                summary("WPS carrier type match - add WPS carrier record")
                 data = wpas_get_handover_sel()
                 if data is None:
-                    print "Could not get handover select carrier record from hostapd"
+                    summary("Could not get handover select carrier record from hostapd")
                     continue
                 print "Handover select carrier record from hostapd:"
                 print data.encode("hex")
-                self.sent_carrier = data
+                if "OK" in wpas_report_handover(carrier.record, data):
+                    success_report("Handover reported successfully")
+                else:
+                    summary("Handover report rejected")
 
                 message = nfc.ndef.Message(data);
                 sel.add_carrier(message[0], "active", message[1:])
 
         print "Handover select:"
-        print sel.pretty()
+        try:
+            print sel.pretty()
+        except Exception, e:
+            print e
         print str(sel).encode("hex")
 
-        print "Sending handover select"
+        summary("Sending handover select")
+        self.success = True
         return sel
 
 
-def wps_handover_resp(peer):
-    print "Trying to handle WPS handover"
-
-    srv = HandoverServer()
-    srv.sent_carrier = None
-
-    nfc.llcp.activate(peer);
-
-    try:
-        print "Trying handover";
-        srv.start()
-        print "Wait for disconnect"
-        while nfc.llcp.connected():
-            time.sleep(0.1)
-        print "Disconnected after handover"
-    except nfc.llcp.ConnectRefused:
-        print "Handover connection refused"
-        nfc.llcp.shutdown()
-        return
-
-    if srv.sent_carrier:
-        wpas_report_handover(srv.received_carrier, srv.sent_carrier)
-
-    print "Remove peer"
-    nfc.llcp.shutdown()
-    print "Done with handover"
-
-
 def wps_tag_read(tag):
+    success = False
     if len(tag.ndef.message):
-        message = nfc.ndef.Message(tag.ndef.message)
-        print "message type " + message.type
-
-        for record in message:
+        for record in tag.ndef.message:
             print "record type " + record.type
             if record.type == "application/vnd.wfa.wsc":
-                print "WPS tag - send to hostapd"
-                wpas_tag_read(tag.ndef.message)
+                summary("WPS tag - send to hostapd")
+                success = wpas_tag_read(tag.ndef.message)
                 break
     else:
-        print "Empty tag"
+        summary("Empty tag")
 
-    print "Remove tag"
-    while tag.is_present:
+    if success:
+        success_report("Tag read succeeded")
+
+    return success
+
+
+def rdwr_connected_write(tag):
+    summary("Tag found - writing - " + str(tag))
+    global write_data
+    tag.ndef.message = str(write_data)
+    success_report("Tag write succeeded")
+    print "Done - remove tag"
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
+    global write_wait_remove
+    while write_wait_remove and tag.is_present:
         time.sleep(0.1)
 
-
-def wps_write_config_tag(clf):
-    print "Write WPS config token"
-    data = wpas_get_config_token()
-    if (data == None):
-        print "Could not get WPS config token from hostapd"
+def wps_write_config_tag(clf, wait_remove=True):
+    summary("Write WPS config token")
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_config_token()
+    if write_data == None:
+        summary("Could not get WPS config token from hostapd")
         return
 
     print "Touch an NFC tag"
-    while True:
-        tag = clf.poll()
-        if tag == None:
-            time.sleep(0.1)
-            continue
-        break
-
-    print "Tag found - writing"
-    tag.ndef.message = data
-    print "Done - remove tag"
-    while tag.is_present:
-        time.sleep(0.1)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-def wps_write_password_tag(clf):
-    print "Write WPS password token"
-    data = wpas_get_password_token()
-    if (data == None):
-        print "Could not get WPS password token from hostapd"
+def wps_write_password_tag(clf, wait_remove=True):
+    summary("Write WPS password token")
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_password_token()
+    if write_data == None:
+        summary("Could not get WPS password token from hostapd")
         return
 
     print "Touch an NFC tag"
-    while True:
-        tag = clf.poll()
-        if tag == None:
-            time.sleep(0.1)
-            continue
-        break
-
-    print "Tag found - writing"
-    tag.ndef.message = data
-    print "Done - remove tag"
-    while tag.is_present:
-        time.sleep(0.1)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-def find_peer(clf):
-    while True:
-        if nfc.llcp.connected():
-            print "LLCP connected"
-        general_bytes = nfc.llcp.startup({})
-        peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
-        if isinstance(peer, nfc.DEP):
-            print "listen -> DEP";
-            if peer.general_bytes.startswith("Ffm"):
-                print "Found DEP"
-                return peer
-            print "mismatch in general_bytes"
-            print peer.general_bytes
+def rdwr_connected(tag):
+    global only_one, no_wait
+    summary("Tag connected: " + str(tag))
 
-        peer = clf.poll(general_bytes)
-        if isinstance(peer, nfc.DEP):
-            print "poll -> DEP";
-            if peer.general_bytes.startswith("Ffm"):
-                print "Found DEP"
-                return peer
-            print "mismatch in general_bytes"
-            print peer.general_bytes
+    if tag.ndef:
+        print "NDEF tag: " + tag.type
+        try:
+            print tag.ndef.message.pretty()
+        except Exception, e:
+            print e
+        success = wps_tag_read(tag)
+        if only_one and success:
+            global continue_loop
+            continue_loop = False
+    else:
+        summary("Not an NDEF tag - remove tag")
+        return True
 
-        if peer:
-            print "Found tag"
-            return peer
+    return not no_wait
+
+
+def llcp_startup(clf, llc):
+    print "Start LLCP server"
+    global srv
+    srv = HandoverServer(llc)
+    return llc
+
+def llcp_connected(llc):
+    print "P2P LLCP connected"
+    global wait_connection
+    wait_connection = False
+    global srv
+    srv.start()
+    return True
 
 
 def main():
     clf = nfc.ContactlessFrontend()
 
+    parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
+    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+                        action='store_const', dest='loglevel',
+                        help='verbose debug output')
+    parser.add_argument('-q', const=logging.WARNING, action='store_const',
+                        dest='loglevel', help='be quiet')
+    parser.add_argument('--only-one', '-1', action='store_true',
+                        help='run only one operation and exit')
+    parser.add_argument('--no-wait', action='store_true',
+                        help='do not wait for tag to be removed before exiting')
+    parser.add_argument('--summary',
+                        help='summary file for writing status updates')
+    parser.add_argument('--success',
+                        help='success file for writing success update')
+    parser.add_argument('command', choices=['write-config',
+                                            'write-password'],
+                        nargs='?')
+    args = parser.parse_args()
+
+    global only_one
+    only_one = args.only_one
+
+    global no_wait
+    no_wait = args.no_wait
+
+    if args.summary:
+        global summary_file
+        summary_file = args.summary
+
+    if args.success:
+        global success_file
+        success_file = args.success
+
+    logging.basicConfig(level=args.loglevel)
+
     try:
-        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
-            wps_write_config_tag(clf)
+        if not clf.open("usb"):
+            print "Could not open connection with an NFC device"
             raise SystemExit
 
-        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
-            wps_write_password_tag(clf)
+        if args.command == "write-config":
+            wps_write_config_tag(clf, wait_remove=not args.no_wait)
             raise SystemExit
 
-        while True:
+        if args.command == "write-password":
+            wps_write_password_tag(clf, wait_remove=not args.no_wait)
+            raise SystemExit
+
+        global continue_loop
+        while continue_loop:
             print "Waiting for a tag or peer to be touched"
+            wait_connection = True
+            try:
+                if not clf.connect(rdwr={'on-connect': rdwr_connected},
+                                   llcp={'on-startup': llcp_startup,
+                                         'on-connect': llcp_connected}):
+                    break
+            except Exception, e:
+                print "clf.connect failed"
 
-            tag = find_peer(clf)
-            if isinstance(tag, nfc.DEP):
-                wps_handover_resp(tag)
-                continue
-
-            if tag.ndef:
-                wps_tag_read(tag)
-                continue
-
-            print "Not an NDEF tag - remove tag"
-            while tag.is_present:
-                time.sleep(0.1)
+            global srv
+            if only_one and srv and srv.success:
+                raise SystemExit
 
     except KeyboardInterrupt:
         raise SystemExit
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 9c41962..adfd3df 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 9540531..6290d3f 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -10,7 +10,6 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
-#include "drivers/driver.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -44,7 +43,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
 			     radius_client_get_id(hapd->radius));
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return NULL;
 	}
 
@@ -55,7 +54,7 @@
 			    sta->acct_session_id_hi, sta->acct_session_id_lo);
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
 					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Acct-Session-Id\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
 			goto fail;
 		}
 	} else {
@@ -64,7 +63,7 @@
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
 				       status_type)) {
-		printf("Could not add Acct-Status-Type\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
 		goto fail;
 	}
 
@@ -74,7 +73,7 @@
 				       hapd->conf->ieee802_1x ?
 				       RADIUS_ACCT_AUTHENTIC_RADIUS :
 				       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
-		printf("Could not add Acct-Authentic\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
 		goto fail;
 	}
 
@@ -99,7 +98,7 @@
 
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
 					 len)) {
-			printf("Could not add User-Name\n");
+			wpa_printf(MSG_INFO, "Could not add User-Name");
 			goto fail;
 		}
 	}
@@ -117,7 +116,7 @@
 
 			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
 						 val, len)) {
-				printf("Could not add Class\n");
+				wpa_printf(MSG_INFO, "Could not add Class");
 				goto fail;
 			}
 		}
@@ -202,7 +201,6 @@
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct radius_msg *msg;
-	struct os_time t;
 	int interval;
 
 	if (sta->acct_session_started)
@@ -213,8 +211,7 @@
 		       "starting accounting session %08X-%08X",
 		       sta->acct_session_id_hi, sta->acct_session_id_lo);
 
-	os_get_time(&t);
-	sta->acct_session_start = t.sec;
+	os_get_reltime(&sta->acct_session_start);
 	sta->last_rx_bytes = sta->last_tx_bytes = 0;
 	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
 	hostapd_drv_sta_clear_stats(hapd, sta->addr);
@@ -244,6 +241,7 @@
 	struct radius_msg *msg;
 	int cause = sta->acct_terminate_cause;
 	struct hostap_sta_driver_data data;
+	struct os_reltime now_r, diff;
 	struct os_time now;
 	u32 gigawords;
 
@@ -254,14 +252,16 @@
 			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
 			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
 	if (!msg) {
-		printf("Could not create RADIUS Accounting message\n");
+		wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
 		return;
 	}
 
+	os_get_reltime(&now_r);
 	os_get_time(&now);
+	os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
-				       now.sec - sta->acct_session_start)) {
-		printf("Could not add Acct-Session-Time\n");
+				       diff.sec)) {
+		wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
 		goto fail;
 	}
 
@@ -269,19 +269,19 @@
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
 					       data.rx_packets)) {
-			printf("Could not add Acct-Input-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
 					       data.tx_packets)) {
-			printf("Could not add Acct-Output-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
 					       data.rx_bytes)) {
-			printf("Could not add Acct-Input-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_input_gigawords;
@@ -292,13 +292,13 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Input-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
 					       data.tx_bytes)) {
-			printf("Could not add Acct-Output-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_output_gigawords;
@@ -309,14 +309,14 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Output-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
 			goto fail;
 		}
 	}
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
 				       now.sec)) {
-		printf("Could not add Event-Timestamp\n");
+		wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
 		goto fail;
 	}
 
@@ -326,7 +326,7 @@
 	if (stop && cause &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       cause)) {
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		goto fail;
 	}
 
@@ -400,13 +400,12 @@
 		   void *data)
 {
 	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
 	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
@@ -432,7 +431,7 @@
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
 	{
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		radius_msg_free(msg);
 		return;
 	}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index d5e3f59..f58b091 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
 #include "utils/common.h"
 #include "utils/list.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
@@ -279,7 +280,7 @@
 }
 
 
-void acs_fail(struct hostapd_iface *iface)
+static void acs_fail(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_ERROR, "ACS: Failed to start");
 	acs_cleanup(iface);
@@ -352,23 +353,13 @@
 }
 
 
-static int acs_usable_chan(struct hostapd_channel_data *chan)
-{
-	if (dl_list_empty(&chan->survey_list))
-		return 0;
-	if (chan->flag & HOSTAPD_CHAN_DISABLED)
-		return 0;
-	return 1;
-}
-
-
 static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
 {
 	const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
 				157, 184, 192 };
 	unsigned int i;
 
-	for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(allowed); i++)
 		if (chan->chan == allowed[i])
 			return 1;
 
@@ -398,28 +389,54 @@
 }
 
 
+static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
+{
+	struct freq_survey *survey;
+
+	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;
+		}
+	}
+
+	return 1;
+
+}
+
+
 static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
 {
 	int i;
 	struct hostapd_channel_data *chan;
-	struct freq_survey *survey;
+	int valid = 0;
 
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
-		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_list_is_sufficient(chan))
+			continue;
+
+		valid++;
 	}
 
+	/* We need at least survey data for one channel */
+	return !!valid;
+}
+
+
+static int acs_usable_chan(struct hostapd_channel_data *chan)
+{
+	if (dl_list_empty(&chan->survey_list))
+		return 0;
+	if (chan->flag & HOSTAPD_CHAN_DISABLED)
+		return 0;
+	if (!acs_survey_list_is_sufficient(chan))
+		return 0;
 	return 1;
 }
 
@@ -456,7 +473,7 @@
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 
-		if (!acs_usable_chan(chan))
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
 		if (chan->freq == freq)
@@ -476,7 +493,8 @@
 static struct hostapd_channel_data *
 acs_find_ideal_chan(struct hostapd_iface *iface)
 {
-	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL;
+	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
+		*rand_chan = NULL;
 	long double factor, ideal_factor = 0;
 	int i, j;
 	int n_chans = 1;
@@ -508,9 +526,10 @@
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
 		chan = &iface->current_mode->channels[i];
 
-		if (!acs_usable_chan(chan))
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
+
 		/* HT40 on 5 GHz has a limited set of primary channels as per
 		 * 11n Annex J */
 		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -522,14 +541,17 @@
 			continue;
 		}
 
-		factor = chan->interference_factor;
+		factor = 0;
+		if (acs_usable_chan(chan))
+			factor = chan->interference_factor;
 
 		for (j = 1; j < n_chans; j++) {
 			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
 			if (!adj_chan)
 				break;
 
-			factor += adj_chan->interference_factor;
+			if (acs_usable_chan(adj_chan))
+				factor += adj_chan->interference_factor;
 		}
 
 		if (j != n_chans) {
@@ -548,22 +570,22 @@
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 10);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 5);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 10);
-				if (adj_chan)
+				if (adj_chan && acs_usable_chan(adj_chan))
 					factor += adj_chan->interference_factor;
 			}
 		}
@@ -571,17 +593,24 @@
 		wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
 			   chan->chan, factor);
 
-		if (!ideal_chan || factor < ideal_factor) {
+		if (acs_usable_chan(chan) &&
+		    (!ideal_chan || factor < ideal_factor)) {
 			ideal_factor = factor;
 			ideal_chan = chan;
 		}
+
+		/* This channel would at least be usable */
+		if (!rand_chan)
+			rand_chan = chan;
 	}
 
-	if (ideal_chan)
+	if (ideal_chan) {
 		wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
 			   ideal_chan->chan, ideal_chan->freq, ideal_factor);
+		return ideal_chan;
+	}
 
-	return ideal_chan;
+	return rand_chan;
 }
 
 
@@ -655,6 +684,7 @@
 	ideal_chan = acs_find_ideal_chan(iface);
 	if (!ideal_chan) {
 		wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
+		err = -1;
 		goto fail;
 	}
 
@@ -663,24 +693,20 @@
 	if (iface->conf->ieee80211ac)
 		acs_adjust_vht_center_freq(iface);
 
+	err = 0;
+fail:
 	/*
 	 * hostapd_setup_interface_complete() will return -1 on failure,
 	 * 0 on success and 0 is HOSTAPD_CHAN_VALID :)
 	 */
-	switch (hostapd_acs_completed(iface)) {
-	case HOSTAPD_CHAN_VALID:
+	if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
 		acs_cleanup(iface);
 		return;
-	case HOSTAPD_CHAN_INVALID:
-	case HOSTAPD_CHAN_ACS:
-	default:
-		/* This can possibly happen if channel parameters (secondary
-		 * channel, center frequencies) are misconfigured */
-		wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
-		goto fail;
 	}
 
-fail:
+	/* This can possibly happen if channel parameters (secondary
+	 * channel, center frequencies) are misconfigured */
+	wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
 	acs_fail(iface);
 }
 
@@ -704,14 +730,17 @@
 		err = acs_request_scan(iface);
 		if (err) {
 			wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
-			acs_fail(iface);
-			return;
+			goto fail;
 		}
 
 		return;
 	}
 
 	acs_study(iface);
+	return;
+fail:
+	hostapd_acs_completed(iface, 1);
+	acs_fail(iface);
 }
 
 
@@ -766,5 +795,8 @@
 	if (err < 0)
 		return HOSTAPD_CHAN_INVALID;
 
+	hostapd_set_state(iface, HAPD_IFACE_ACS);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
+
 	return HOSTAPD_CHAN_ACS;
 }
diff --git a/src/ap/acs.h b/src/ap/acs.h
index 0d1d0f1..fc85259 100644
--- a/src/ap/acs.h
+++ b/src/ap/acs.h
@@ -13,7 +13,6 @@
 #ifdef CONFIG_ACS
 
 enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
-int hostapd_acs_completed(struct hostapd_iface *iface);
 
 #else /* CONFIG_ACS */
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index caf75c4..368b202 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -130,9 +130,17 @@
 		os_free(bss);
 		return NULL;
 	}
+	conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
+	if (conf->bss == NULL) {
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+	conf->bss[0] = bss;
 
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
+		os_free(conf->bss);
 		os_free(conf);
 		os_free(bss);
 		return NULL;
@@ -141,7 +149,6 @@
 	hostapd_config_defaults_bss(bss);
 
 	conf->num_bss = 1;
-	conf->bss = bss;
 
 	conf->beacon_int = 100;
 	conf->rts_threshold = -1; /* use driver default: 2347 */
@@ -397,7 +404,7 @@
 }
 
 
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
 	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
@@ -427,15 +434,16 @@
 	}
 	os_free(conf->eap_user_sqlite);
 
-	os_free(conf->dump_log_name);
 	os_free(conf->eap_req_id_text);
 	os_free(conf->accept_mac);
 	os_free(conf->deny_mac);
 	os_free(conf->nas_identifier);
-	hostapd_config_free_radius(conf->radius->auth_servers,
-				   conf->radius->num_auth_servers);
-	hostapd_config_free_radius(conf->radius->acct_servers,
-				   conf->radius->num_acct_servers);
+	if (conf->radius) {
+		hostapd_config_free_radius(conf->radius->auth_servers,
+					   conf->radius->num_auth_servers);
+		hostapd_config_free_radius(conf->radius->acct_servers,
+					   conf->radius->num_acct_servers);
+	}
 	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
 	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
 	os_free(conf->rsn_preauth_interfaces);
@@ -525,6 +533,8 @@
 	os_free(conf->sae_groups);
 
 	os_free(conf->server_id);
+
+	os_free(conf);
 }
 
 
@@ -540,7 +550,7 @@
 		return;
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_config_free_bss(&conf->bss[i]);
+		hostapd_config_free_bss(conf->bss[i]);
 	os_free(conf->bss);
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
@@ -658,3 +668,218 @@
 
 	return NULL;
 }
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf,
+				    int full_config)
+{
+	if (full_config && bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
+		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+			   "EAP authenticator configured).");
+		return -1;
+	}
+
+	if (bss->wpa) {
+		int wep, i;
+
+		wep = bss->default_wep_key_len > 0 ||
+		       bss->individual_wep_key_len > 0;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (bss->ssid.wep.keys_set) {
+				wep = 1;
+				break;
+			}
+		}
+
+		if (wep) {
+			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
+			return -1;
+		}
+	}
+
+	if (full_config && bss->wpa &&
+	    bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
+	if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+			   "is not configured.");
+		return -1;
+	}
+
+	if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if (conf->bss[i] != bss &&
+			    (hostapd_mac_comp(conf->bss[i]->bssid,
+					      bss->bssid) == 0)) {
+				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+					   " on interface '%s' and '%s'.",
+					   MAC2STR(bss->bssid),
+					   conf->bss[i]->iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    (bss->nas_identifier == NULL ||
+	     os_strlen(bss->nas_identifier) < 1 ||
+	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+			   "nas_identifier to be configured as a 1..48 octet "
+			   "string");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+	if (full_config && conf->ieee80211n &&
+	    conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+			   "allowed, disabling HT capabilites");
+	}
+
+	if (full_config && conf->ieee80211n &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+			   "allowed, disabling HT capabilities");
+	}
+
+	if (full_config && conf->ieee80211n && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+	{
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+			   "requires CCMP/GCMP to be enabled, disabling HT "
+			   "capabilities");
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+	if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
+		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+			   "configuration forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+
+	if (full_config && bss->wps_state &&
+	    bss->ssid.wep.keys_set && bss->wpa == 0) {
+		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+			   "disabled");
+		bss->wps_state = 0;
+	}
+
+	if (full_config && bss->wps_state && bss->wpa &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+			   "WPA2/CCMP forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+	if (full_config && bss->hs20 &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+				    WPA_CIPHER_CCMP_256 |
+				    WPA_CIPHER_GCMP_256)))) {
+		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+			   "configuration is required for Hotspot 2.0 "
+			   "functionality");
+		return -1;
+	}
+#endif /* CONFIG_HS20 */
+
+	return 0;
+}
+
+
+int hostapd_config_check(struct hostapd_config *conf, int full_config)
+{
+	size_t i;
+
+	if (full_config && conf->ieee80211d &&
+	    (!conf->country[0] || !conf->country[1])) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+			   "setting the country_code");
+		return -1;
+	}
+
+	if (full_config && conf->ieee80211h && !conf->ieee80211d) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+			   "IEEE 802.11d enabled");
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for
+		 * broadcast keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+		bss->rsn_pairwise = bss->wpa_pairwise;
+	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+						    bss->rsn_pairwise);
+
+	bss->radius->auth_server = bss->radius->auth_servers;
+	bss->radius->acct_server = bss->radius->acct_servers;
+
+	if (bss->wpa && bss->ieee802_1x) {
+		bss->ssid.security_policy = SECURITY_WPA;
+	} else if (bss->wpa) {
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	} else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c5531fa..4631ca9 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -53,6 +53,8 @@
 	size_t ssid_len;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
+	unsigned int wpa_passphrase_set:1;
+	unsigned int wpa_psk_set:1;
 
 	char vlan[IFNAMSIZ + 1];
 	secpolicy security_policy;
@@ -187,8 +189,6 @@
 	unsigned int logger_syslog; /* module bitfield */
 	unsigned int logger_stdout; /* module bitfield */
 
-	char *dump_log_name; /* file name for state dump (SIGUSR1) */
-
 	int max_num_sta; /* maximum number of STAs in station table */
 
 	int dtim_period;
@@ -311,6 +311,7 @@
 
 	char *radius_server_clients;
 	int radius_server_auth_port;
+	int radius_server_acct_port;
 	int radius_server_ipv6;
 
 	char *test_socket; /* UNIX domain socket path for driver_test */
@@ -384,6 +385,12 @@
 #define P2P_MANAGE BIT(3)
 #define P2P_ALLOW_CROSS_CONNECTION BIT(4)
 	int p2p;
+#ifdef CONFIG_P2P
+	u8 ip_addr_go[4];
+	u8 ip_addr_mask[4];
+	u8 ip_addr_start[4];
+	u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
 
 	int disassoc_low_ack;
 	int skip_inactivity_poll;
@@ -442,6 +449,9 @@
 	u16 gas_comeback_delay;
 	int gas_frag_limit;
 
+	u8 qos_map_set[16 + 2 * 21];
+	unsigned int qos_map_set_len;
+
 #ifdef CONFIG_HS20
 	int hs20;
 	int disable_dgaf;
@@ -464,6 +474,11 @@
 
 	unsigned int sae_anti_clogging_threshold;
 	int *sae_groups;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 bss_load_test[5];
+	u8 bss_load_test_set;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -471,7 +486,7 @@
  * struct hostapd_config - Per-radio interface configuration
  */
 struct hostapd_config {
-	struct hostapd_bss_config *bss, *last_bss;
+	struct hostapd_bss_config **bss, *last_bss;
 	size_t num_bss;
 
 	u16 beacon_int;
@@ -520,6 +535,7 @@
 	int ieee80211n;
 	int secondary_channel;
 	int require_ht;
+	int obss_interval;
 	u32 vht_capab;
 	int ieee80211ac;
 	int require_vht;
@@ -545,6 +561,7 @@
 int hostapd_mac_comp_empty(const void *a);
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+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,
 			  const u8 *addr, int *vlan_id);
@@ -560,5 +577,7 @@
 					int vlan_id);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+int hostapd_config_check(struct hostapd_config *conf, int full_config);
+void hostapd_set_security_params(struct hostapd_bss_config *bss);
 
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 3072562..e998fc6 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -9,7 +9,6 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
-#include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "wps/wps.h"
 #include "p2p/p2p.h"
@@ -286,7 +285,7 @@
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
 	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
-			      NULL, NULL, force_ifname, if_addr, NULL);
+			      NULL, NULL, force_ifname, if_addr, NULL, 0);
 }
 
 
@@ -347,7 +346,7 @@
 		    u16 listen_interval,
 		    const struct ieee80211_ht_capabilities *ht_capab,
 		    const struct ieee80211_vht_capabilities *vht_capab,
-		    u32 flags, u8 qosinfo)
+		    u32 flags, u8 qosinfo, u8 vht_opmode)
 {
 	struct hostapd_sta_add_params params;
 
@@ -365,6 +364,8 @@
 	params.listen_interval = listen_interval;
 	params.ht_capabilities = ht_capab;
 	params.vht_capabilities = vht_capab;
+	params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
+	params.vht_opmode = vht_opmode;
 	params.flags = hostapd_sta_flags_to_drv(flags);
 	params.qosinfo = qosinfo;
 	return hapd->driver->sta_add(hapd->drv_priv, &params);
@@ -417,20 +418,21 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge)
+		   const char *bridge, int use_existing)
 {
 	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
 		return -1;
 	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
 				    bss_ctx, drv_priv, force_ifname, if_addr,
-				    bridge);
+				    bridge, use_existing);
 }
 
 
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname)
 {
-	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->if_remove == NULL)
 		return -1;
 	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
 }
@@ -463,44 +465,50 @@
 }
 
 
-int hostapd_set_freq(struct hostapd_data *hapd, 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)
+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)
 {
-	struct hostapd_freq_params data;
 	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;
+	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) {
+	if (data->vht_enabled) switch (vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
 		if (center_segment1)
 			return -1;
-		if (5000 + center_segment0 * 5 != data.center_freq1)
+		if (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;
+		data->center_freq2 = 5000 + center_segment1 * 5;
 		/* fall through */
 	case VHT_CHANWIDTH_80MHZ:
-		data.bandwidth = 80;
+		data->bandwidth = 80;
 		if (vht_oper_chwidth == 1 && center_segment1)
 			return -1;
 		if (vht_oper_chwidth == 3 && !center_segment1)
@@ -510,13 +518,19 @@
 		/* primary 40 part must match the HT configuration */
 		tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
 		tmp /= 2;
-		if (data.center_freq1 != 5000 +
+		if (data->center_freq1 != 5000 +
 					 center_segment0 * 5 - 20 + 40 * tmp)
 			return -1;
-		data.center_freq1 = 5000 + center_segment0 * 5;
+		data->center_freq1 = 5000 + center_segment0 * 5;
 		break;
 	case VHT_CHANWIDTH_160MHZ:
-		data.bandwidth = 160;
+		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)
@@ -524,12 +538,31 @@
 		/* primary 40 part must match the HT configuration */
 		tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
 		tmp /= 2;
-		if (data.center_freq1 != 5000 +
+		if (data->center_freq1 != 5000 +
 					 center_segment0 * 5 - 60 + 40 * tmp)
 			return -1;
-		data.center_freq1 = 5000 + center_segment0 * 5;
+		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 sec_channel_offset, int vht_oper_chwidth,
+		     int center_segment0, int center_segment1)
+{
+	struct hostapd_freq_params data;
+
+	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+				    vht_enabled, sec_channel_offset,
+				    vht_oper_chwidth,
+				    center_segment0, center_segment1,
+				    hapd->iface->current_mode->vht_capab))
+		return -1;
+
 	if (hapd->driver == NULL)
 		return 0;
 	if (hapd->driver->set_freq == NULL)
@@ -683,7 +716,7 @@
 			 const u8 *peer, u8 *buf, u16 *buf_len)
 {
 	if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
-		return 0;
+		return -1;
 	return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
 				      buf_len);
 }
@@ -699,3 +732,46 @@
 					 hapd->own_addr, hapd->own_addr, data,
 					 len, 0);
 }
+
+
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, 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)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_freq_params data;
+	int res;
+
+	if (!hapd->driver || !hapd->driver->start_dfs_cac)
+		return 0;
+
+	if (!iface->conf->ieee80211h) {
+		wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
+			   "is not enabled");
+		return -1;
+	}
+
+	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+				    vht_enabled, sec_channel_offset,
+				    vht_oper_chwidth, center_segment0,
+				    center_segment1,
+				    iface->current_mode->vht_capab))
+		return -1;
+
+	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+	if (!res)
+		iface->cac_started = 1;
+
+	return res;
+}
+
+
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
+			    const u8 *qos_map_set, u8 qos_map_set_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+		return 0;
+	return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
+					 qos_map_set_len);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 23277b6..9edaf7d 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -1,6 +1,6 @@
 /*
  * hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,7 @@
 struct wpa_driver_scan_params;
 struct ieee80211_ht_capabilities;
 struct ieee80211_vht_capabilities;
+struct hostapd_freq_params;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
 int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -39,7 +40,7 @@
 		    u16 listen_interval,
 		    const struct ieee80211_ht_capabilities *ht_capab,
 		    const struct ieee80211_vht_capabilities *vht_capab,
-		    u32 flags, u8 qosinfo);
+		    u32 flags, u8 qosinfo, u8 vht_opmode);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
 			     size_t elem_len);
@@ -48,7 +49,7 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge);
+		   const char *bridge, int use_existing);
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname);
 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -101,6 +102,15 @@
 		      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 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);
 
 
 #include "drivers/driver.h"
@@ -109,6 +119,9 @@
 			 enum wnm_oper oper, const u8 *peer,
 			 u8 *buf, u16 *buf_len);
 
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
+			    u8 qos_map_set_len);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
 						  int enabled)
 {
@@ -235,4 +248,36 @@
 	return hapd->driver->get_survey(hapd->drv_priv, freq);
 }
 
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+	if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+		return -1;
+	return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
+static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->get_radio_name == NULL)
+		return NULL;
+	return hapd->driver->get_radio_name(hapd->drv_priv);
+}
+
+static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
+					     struct csa_settings *settings)
+{
+	if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
+		return -ENOTSUP;
+
+	return hapd->driver->switch_channel(hapd->drv_priv, settings);
+}
+
+static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
+				     size_t buflen)
+{
+	if (hapd->driver == NULL || hapd->driver->status == NULL)
+		return -1;
+	return hapd->driver->status(hapd->drv_priv, buf, buflen);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 9f02151..287d520 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -14,7 +14,6 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
@@ -33,7 +32,8 @@
 {
 	int i;
 
-	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+	if (iface->current_mode == NULL ||
+	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
 	    iface->conf->channel != ap->channel)
 		return 0;
 
@@ -172,7 +172,6 @@
 			    struct hostapd_frame_info *fi)
 {
 	struct ap_info *ap;
-	struct os_time now;
 	int new_ap = 0;
 	int set_beacon = 0;
 
@@ -210,8 +209,7 @@
 	else
 		ap->ht_support = 0;
 
-	os_get_time(&now);
-	ap->last_beacon = now.sec;
+	os_get_reltime(&ap->last_beacon);
 
 	if (!new_ap && ap != iface->ap_list) {
 		/* move AP entry into the beginning of the list so that the
@@ -252,7 +250,7 @@
 static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
 {
 	struct hostapd_iface *iface = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 	struct ap_info *ap;
 	int set_beacon = 0;
 
@@ -261,12 +259,12 @@
 	if (!iface->ap_list)
 		return;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	while (iface->ap_list) {
 		ap = iface->ap_list->prev;
-		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
-		    now.sec)
+		if (!os_reltime_expired(&now, &ap->last_beacon,
+					iface->conf->ap_table_expiration_time))
 			break;
 
 		ap_free_ap(iface, ap);
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index d0529a1..93dc0ed 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -26,7 +26,7 @@
 
 	int ht_support;
 
-	os_time_t last_beacon;
+	struct os_reltime last_beacon;
 };
 
 struct ieee802_11_elems;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 68ad4dc..7183aba 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -92,6 +92,7 @@
 	os_memset(&srv, 0, sizeof(srv));
 	srv.client_file = conf->radius_server_clients;
 	srv.auth_port = conf->radius_server_auth_port;
+	srv.acct_port = conf->radius_server_acct_port;
 	srv.conf_ctx = hapd;
 	srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
 	srv.ssl_ctx = hapd->ssl_ctx;
@@ -133,7 +134,7 @@
 #ifdef EAP_TLS_FUNCS
 	if (hapd->conf->eap_server &&
 	    (hapd->conf->ca_cert || hapd->conf->server_cert ||
-	     hapd->conf->dh_file)) {
+	     hapd->conf->private_key || hapd->conf->dh_file)) {
 		struct tls_connection_params params;
 
 		hapd->ssl_ctx = tls_init(NULL);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2f4ba23..b1ebf6e 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -4,14 +4,8 @@
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -21,7 +15,6 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
 #include "wps/wps_defs.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -38,6 +31,22 @@
 
 #ifdef NEED_AP_MLME
 
+static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->bss_load_test_set) {
+		if (2 + 5 > len)
+			return eid;
+		*eid++ = WLAN_EID_BSS_LOAD;
+		*eid++ = 5;
+		os_memcpy(eid, hapd->conf->bss_load_test, 5);
+		eid += 5;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	return eid;
+}
+
+
 static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
 {
 	u8 erp = 0;
@@ -187,6 +196,70 @@
 }
 
 
+static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 chan;
+
+	if (!hapd->iface->cs_freq_params.freq)
+		return eid;
+
+	if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) ==
+	    NUM_HOSTAPD_MODES)
+		return eid;
+
+	*eid++ = WLAN_EID_CHANNEL_SWITCH;
+	*eid++ = 3;
+	*eid++ = hapd->iface->cs_block_tx;
+	*eid++ = chan;
+	*eid++ = hapd->iface->cs_count;
+
+	return eid;
+}
+
+
+static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 sec_ch;
+
+	if (!hapd->iface->cs_freq_params.sec_channel_offset)
+		return eid;
+
+	if (hapd->iface->cs_freq_params.sec_channel_offset == -1)
+		sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
+	else if (hapd->iface->cs_freq_params.sec_channel_offset == 1)
+		sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
+	else
+		return eid;
+
+	*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
+	*eid++ = 1;
+	*eid++ = sec_ch;
+
+	return eid;
+}
+
+
+static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
+				  u8 *start, unsigned int *csa_counter_off)
+{
+	u8 *old_pos = pos;
+
+	if (!csa_counter_off)
+		return pos;
+
+	*csa_counter_off = 0;
+	pos = hostapd_eid_csa(hapd, pos);
+
+	if (pos != old_pos) {
+		/* save an offset to the counter - should be last byte */
+		*csa_counter_off = pos - start - 1;
+		pos = hostapd_eid_secondary_channel(hapd, pos);
+	}
+
+	return pos;
+}
+
+
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 				   struct sta_info *sta,
 				   const struct ieee80211_mgmt *req,
@@ -251,6 +324,8 @@
 	/* RSN, MDIE, WPA */
 	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
 
+	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
+
 #ifdef CONFIG_IEEE80211N
 	pos = hostapd_eid_ht_capabilities(hapd, pos);
 	pos = hostapd_eid_ht_operation(hapd, pos);
@@ -265,6 +340,8 @@
 	pos = hostapd_eid_adv_proto(hapd, pos);
 	pos = hostapd_eid_roaming_consortium(hapd, pos);
 
+	pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
+				    &hapd->iface->cs_c_off_proberesp);
 #ifdef CONFIG_IEEE80211AC
 	pos = hostapd_eid_vht_capabilities(hapd, pos);
 	pos = hostapd_eid_vht_operation(hapd, pos);
@@ -443,12 +520,10 @@
 			sta->ssid_probe = &hapd->conf->ssid;
 	} else {
 		if (!(mgmt->da[0] & 0x01)) {
-			char ssid_txt[33];
-			ieee802_11_print_ssid(ssid_txt, elems.ssid,
-					      elems.ssid_len);
 			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
 				   " for foreign SSID '%s' (DA " MACSTR ")%s",
-				   MAC2STR(mgmt->sa), ssid_txt,
+				   MAC2STR(mgmt->sa),
+				   wpa_ssid_txt(elems.ssid, elems.ssid_len),
 				   MAC2STR(mgmt->da),
 				   elems.ssid_list ? " (SSID list)" : "");
 		}
@@ -522,7 +597,7 @@
 		   is_broadcast_ether_addr(mgmt->da));
 
 	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
-		perror("handle_probe_req: send");
+		wpa_printf(MSG_INFO, "handle_probe_req: send failed");
 
 	os_free(resp);
 
@@ -570,23 +645,17 @@
 #endif /* NEED_AP_MLME */
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+			       struct wpa_driver_ap_params *params)
 {
 	struct ieee80211_mgmt *head = NULL;
 	u8 *tail = NULL;
 	size_t head_len = 0, tail_len = 0;
 	u8 *resp = NULL;
 	size_t resp_len = 0;
-	struct wpa_driver_ap_params params;
-	struct wpabuf *beacon, *proberesp, *assocresp;
 #ifdef NEED_AP_MLME
 	u16 capab_info;
 	u8 *pos, *tailpos;
-#endif /* NEED_AP_MLME */
-
-	hapd->beacon_set_done = 1;
-
-#ifdef NEED_AP_MLME
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -607,7 +676,7 @@
 		wpa_printf(MSG_ERROR, "Failed to set beacon data");
 		os_free(head);
 		os_free(tail);
-		return;
+		return -1;
 	}
 
 	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -662,6 +731,9 @@
 	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
 				  tailpos);
 
+	tailpos = hostapd_eid_bss_load(hapd, tailpos,
+				       tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
 #ifdef CONFIG_IEEE80211N
 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
 	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
@@ -678,7 +750,8 @@
 	tailpos = hostapd_eid_interworking(hapd, tailpos);
 	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
 	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
-
+	tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
+					&hapd->iface->cs_c_off_beacon);
 #ifdef CONFIG_IEEE80211AC
 	tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
 	tailpos = hostapd_eid_vht_operation(hapd, tailpos);
@@ -723,94 +796,144 @@
 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
 #endif /* NEED_AP_MLME */
 
-	os_memset(&params, 0, sizeof(params));
-	params.head = (u8 *) head;
-	params.head_len = head_len;
-	params.tail = tail;
-	params.tail_len = tail_len;
-	params.proberesp = resp;
-	params.proberesp_len = resp_len;
-	params.dtim_period = hapd->conf->dtim_period;
-	params.beacon_int = hapd->iconf->beacon_int;
-	params.basic_rates = hapd->iface->basic_rates;
-	params.ssid = hapd->conf->ssid.ssid;
-	params.ssid_len = hapd->conf->ssid.ssid_len;
-	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+	os_memset(params, 0, sizeof(*params));
+	params->head = (u8 *) head;
+	params->head_len = head_len;
+	params->tail = tail;
+	params->tail_len = tail_len;
+	params->proberesp = resp;
+	params->proberesp_len = resp_len;
+	params->dtim_period = hapd->conf->dtim_period;
+	params->beacon_int = hapd->iconf->beacon_int;
+	params->basic_rates = hapd->iface->basic_rates;
+	params->ssid = hapd->conf->ssid.ssid;
+	params->ssid_len = hapd->conf->ssid.ssid_len;
+	params->pairwise_ciphers = hapd->conf->rsn_pairwise ?
 		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
-	params.group_cipher = hapd->conf->wpa_group;
-	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
-	params.auth_algs = hapd->conf->auth_algs;
-	params.wpa_version = hapd->conf->wpa;
-	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+	params->group_cipher = hapd->conf->wpa_group;
+	params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params->auth_algs = hapd->conf->auth_algs;
+	params->wpa_version = hapd->conf->wpa;
+	params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
 		(hapd->conf->ieee802_1x &&
 		 (hapd->conf->default_wep_key_len ||
 		  hapd->conf->individual_wep_key_len));
 	switch (hapd->conf->ignore_broadcast_ssid) {
 	case 0:
-		params.hide_ssid = NO_SSID_HIDING;
+		params->hide_ssid = NO_SSID_HIDING;
 		break;
 	case 1:
-		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
 		break;
 	case 2:
-		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
 		break;
 	}
-	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
-	params.beacon_ies = beacon;
-	params.proberesp_ies = proberesp;
-	params.assocresp_ies = assocresp;
-	params.isolate = hapd->conf->isolate;
+	params->isolate = hapd->conf->isolate;
 #ifdef NEED_AP_MLME
-	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+	params->cts_protect = !!(ieee802_11_erp_info(hapd) &
 				ERP_INFO_USE_PROTECTION);
-	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+	params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
 		hapd->iconf->preamble == SHORT_PREAMBLE;
 	if (hapd->iface->current_mode &&
 	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
-		params.short_slot_time =
+		params->short_slot_time =
 			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
 	else
-		params.short_slot_time = -1;
+		params->short_slot_time = -1;
 	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
-		params.ht_opmode = -1;
+		params->ht_opmode = -1;
 	else
-		params.ht_opmode = hapd->iface->ht_op_mode;
+		params->ht_opmode = hapd->iface->ht_op_mode;
 #endif /* NEED_AP_MLME */
-	params.interworking = hapd->conf->interworking;
+	params->interworking = hapd->conf->interworking;
 	if (hapd->conf->interworking &&
 	    !is_zero_ether_addr(hapd->conf->hessid))
-		params.hessid = hapd->conf->hessid;
-	params.access_network_type = hapd->conf->access_network_type;
-	params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+		params->hessid = hapd->conf->hessid;
+	params->access_network_type = hapd->conf->access_network_type;
+	params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
 #ifdef CONFIG_HS20
-	params.disable_dgaf = hapd->conf->disable_dgaf;
+	params->disable_dgaf = hapd->conf->disable_dgaf;
 #endif /* CONFIG_HS20 */
-	if (hostapd_drv_set_ap(hapd, &params))
-		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
-	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
-
-	os_free(tail);
-	os_free(head);
-	os_free(resp);
+	return 0;
 }
 
 
-void ieee802_11_set_beacons(struct hostapd_iface *iface)
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
+{
+	os_free(params->tail);
+	params->tail = NULL;
+	os_free(params->head);
+	params->head = NULL;
+	os_free(params->proberesp);
+	params->proberesp = NULL;
+}
+
+
+int ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int res, ret = -1;
+
+	if (hapd->iface->csa_in_progress) {
+		wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
+		return -1;
+	}
+
+	hapd->beacon_set_done = 1;
+
+	if (ieee802_11_build_ap_params(hapd, &params) < 0)
+		return -1;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		goto fail;
+
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+
+	res = hostapd_drv_set_ap(hapd, &params);
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+	if (res)
+		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	else
+		ret = 0;
+fail:
+	ieee802_11_free_ap_params(&params);
+	return ret;
+}
+
+
+int ieee802_11_set_beacons(struct hostapd_iface *iface)
 {
 	size_t i;
-	for (i = 0; i < iface->num_bss; i++)
-		ieee802_11_set_beacon(iface->bss[i]);
+	int ret = 0;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		if (iface->bss[i]->started &&
+		    ieee802_11_set_beacon(iface->bss[i]) < 0)
+			ret = -1;
+	}
+
+	return ret;
 }
 
 
 /* only update beacons if started */
-void ieee802_11_update_beacons(struct hostapd_iface *iface)
+int ieee802_11_update_beacons(struct hostapd_iface *iface)
 {
 	size_t i;
-	for (i = 0; i < iface->num_bss; i++)
-		if (iface->bss[i]->beacon_set_done)
-			ieee802_11_set_beacon(iface->bss[i]);
+	int ret = 0;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
+		    ieee802_11_set_beacon(iface->bss[i]) < 0)
+			ret = -1;
+	}
+
+	return ret;
 }
 
 #endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index 37f10d2..722159a 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -3,14 +3,8 @@
  * Copyright (c) 2002-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef BEACON_H
@@ -21,8 +15,11 @@
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len,
 		      int ssi_signal);
-void ieee802_11_set_beacon(struct hostapd_data *hapd);
-void ieee802_11_set_beacons(struct hostapd_iface *iface);
-void ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_set_beacon(struct hostapd_data *hapd);
+int ieee802_11_set_beacons(struct hostapd_iface *iface);
+int ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+			       struct wpa_driver_ap_params *params);
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
 
 #endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1cb7e73..8c0cbab 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, 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 "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
@@ -21,25 +22,61 @@
 #include "ap_drv_ops.h"
 
 
+static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
+				 struct sta_info *sta,
+				 char *buf, size_t buflen)
+{
+	struct hostap_sta_driver_data data;
+	int ret;
+
+	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+		return 0;
+
+	ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
+			  "rx_bytes=%lu\ntx_bytes=%lu\n",
+			  data.rx_packets, data.tx_packets,
+			  data.rx_bytes, data.tx_bytes);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	return ret;
+}
+
+
 static int hostapd_get_sta_conn_time(struct sta_info *sta,
 				     char *buf, size_t buflen)
 {
-	struct os_time now, age;
-	int len = 0, ret;
+	struct os_reltime age;
+	int ret;
 
 	if (!sta->connected_time.sec)
 		return 0;
 
-	os_get_time(&now);
-	os_time_sub(&now, &sta->connected_time, &age);
+	os_reltime_age(&sta->connected_time, &age);
 
-	ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+	ret = os_snprintf(buf, buflen, "connected_time=%u\n",
 			  (unsigned int) age.sec);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	return ret;
+}
 
-	return len;
+
+static const char * timeout_next_str(int val)
+{
+	switch (val) {
+	case STA_NULLFUNC:
+		return "NULLFUNC POLL";
+	case STA_DISASSOC:
+		return "DISASSOC";
+	case STA_DEAUTH:
+		return "DEAUTH";
+	case STA_REMOVE:
+		return "REMOVE";
+	case STA_DISASSOC_FROM_CLI:
+		return "DISASSOC_FROM_CLI";
+	}
+
+	return "?";
 }
 
 
@@ -47,22 +84,45 @@
 				      struct sta_info *sta,
 				      char *buf, size_t buflen)
 {
-	int len, res, ret;
+	int len, res, ret, i;
 
-	if (sta == NULL) {
-		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
-			return 0;
-		return ret;
-	}
+	if (!sta)
+		return 0;
 
 	len = 0;
-	ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
+	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
 			  MAC2STR(sta->addr));
 	if (ret < 0 || (size_t) ret >= buflen - len)
 		return len;
 	len += ret;
 
+	ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
+	if (ret < 0)
+		return len;
+	len += ret;
+
+	ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
+			  "listen_interval=%d\nsupported_rates=",
+			  sta->aid, sta->capability, sta->listen_interval);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	for (i = 0; i < sta->supported_rates_len; i++) {
+		ret = os_snprintf(buf + len, buflen - len, "%02x%s",
+				  sta->supported_rates[i],
+				  i + 1 < sta->supported_rates_len ? " " : "");
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
+			  timeout_next_str(sta->timeout_next));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
 	if (res >= 0)
 		len += res;
@@ -80,9 +140,8 @@
 	if (res >= 0)
 		len += res;
 
-	res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
-	if (res >= 0)
-		len += res;
+	len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
+	len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
 
 	return len;
 }
@@ -100,6 +159,8 @@
 {
 	u8 addr[ETH_ALEN];
 	int ret;
+	const char *pos;
+	struct sta_info *sta;
 
 	if (hwaddr_aton(txtaddr, addr)) {
 		ret = os_snprintf(buf, buflen, "FAIL\n");
@@ -107,8 +168,28 @@
 			return 0;
 		return ret;
 	}
-	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
-					  buf, buflen);
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	pos = os_strchr(txtaddr, ' ');
+	if (pos) {
+		pos++;
+
+#ifdef HOSTAPD_DUMP_STATE
+		if (os_strcmp(pos, "eapol") == 0) {
+			if (sta->eapol_sm == NULL)
+				return -1;
+			return eapol_auth_dump_state(sta->eapol_sm, buf,
+						     buflen);
+		}
+#endif /* HOSTAPD_DUMP_STATE */
+
+		return -1;
+	}
+
+	return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
 }
 
 
@@ -125,7 +206,11 @@
 		if (ret < 0 || (size_t) ret >= buflen)
 			return 0;
 		return ret;
-	}		
+	}
+
+	if (!sta->next)
+		return 0;
+
 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
 }
 
@@ -303,3 +388,123 @@
 
 	return 0;
 }
+
+
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	int len = 0, ret;
+	size_t i;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "state=%s\n"
+			  "phy=%s\n"
+			  "freq=%d\n"
+			  "num_sta_non_erp=%d\n"
+			  "num_sta_no_short_slot_time=%d\n"
+			  "num_sta_no_short_preamble=%d\n"
+			  "olbc=%d\n"
+			  "num_sta_ht_no_gf=%d\n"
+			  "num_sta_no_ht=%d\n"
+			  "num_sta_ht_20_mhz=%d\n"
+			  "olbc_ht=%d\n"
+			  "ht_op_mode=0x%x\n",
+			  hostapd_state_text(iface->state),
+			  iface->phy,
+			  iface->freq,
+			  iface->num_sta_non_erp,
+			  iface->num_sta_no_short_slot_time,
+			  iface->num_sta_no_short_preamble,
+			  iface->olbc,
+			  iface->num_sta_ht_no_gf,
+			  iface->num_sta_no_ht,
+			  iface->num_sta_ht_20mhz,
+			  iface->olbc_ht,
+			  iface->ht_op_mode);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "channel=%u\n"
+			  "secondary_channel=%d\n"
+			  "ieee80211n=%d\n"
+			  "ieee80211ac=%d\n"
+			  "vht_oper_chwidth=%d\n"
+			  "vht_oper_centr_freq_seg0_idx=%d\n"
+			  "vht_oper_centr_freq_seg1_idx=%d\n",
+			  iface->conf->channel,
+			  iface->conf->secondary_channel,
+			  iface->conf->ieee80211n,
+			  iface->conf->ieee80211ac,
+			  iface->conf->vht_oper_chwidth,
+			  iface->conf->vht_oper_centr_freq_seg0_idx,
+			  iface->conf->vht_oper_centr_freq_seg1_idx);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		ret = os_snprintf(buf + len, buflen - len,
+				  "bss[%d]=%s\n"
+				  "bssid[%d]=" MACSTR "\n"
+				  "ssid[%d]=%s\n"
+				  "num_sta[%d]=%d\n",
+				  (int) i, bss->conf->iface,
+				  (int) i, MAC2STR(bss->own_addr),
+				  (int) i,
+				  wpa_ssid_txt(bss->conf->ssid.ssid,
+					       bss->conf->ssid.ssid_len),
+				  (int) i, bss->num_sta);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
+
+
+int hostapd_parse_csa_settings(const char *pos,
+			       struct csa_settings *settings)
+{
+	char *end;
+
+	if (!settings)
+		return -1;
+
+	os_memset(settings, 0, sizeof(*settings));
+	settings->cs_count = strtol(pos, &end, 10);
+	if (pos == end) {
+		wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
+		return -1;
+	}
+
+	settings->freq_params.freq = atoi(end);
+	if (settings->freq_params.freq == 0) {
+		wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
+		return -1;
+	}
+
+#define SET_CSA_SETTING(str) \
+	do { \
+		const char *pos2 = os_strstr(pos, " " #str "="); \
+		if (pos2) { \
+			pos2 += sizeof(" " #str "=") - 1; \
+			settings->freq_params.str = atoi(pos2); \
+		} \
+	} while (0)
+
+	SET_CSA_SETTING(center_freq1);
+	SET_CSA_SETTING(center_freq2);
+	SET_CSA_SETTING(bandwidth);
+	SET_CSA_SETTING(sec_channel_offset);
+	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
+	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+	settings->block_tx = !!os_strstr(pos, " blocktx");
+#undef SET_CSA_SETTING
+
+	return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e83f894..ee58b4c 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,5 +19,10 @@
 				      const char *txtaddr);
 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
 				    const char *txtaddr);
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen);
+int hostapd_parse_csa_settings(const char *pos,
+			       struct csa_settings *settings);
+
 
 #endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
new file mode 100644
index 0000000..ec691db
--- /dev/null
+++ b/src/ap/dfs.c
@@ -0,0 +1,803 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "drivers/driver.h"
+#include "dfs.h"
+
+
+static int dfs_get_used_n_chans(struct hostapd_iface *iface)
+{
+	int n_chans = 1;
+
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
+		n_chans = 2;
+
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
+		case VHT_CHANWIDTH_USE_HT:
+			break;
+		case VHT_CHANWIDTH_80MHZ:
+			n_chans = 4;
+			break;
+		case VHT_CHANWIDTH_160MHZ:
+			n_chans = 8;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return n_chans;
+}
+
+
+static int dfs_channel_available(struct hostapd_channel_data *chan,
+				 int skip_radar)
+{
+	/*
+	 * When radar detection happens, CSA is performed. However, there's no
+	 * time for CAC, so radar channels must be skipped when finding a new
+	 * channel for CSA.
+	 */
+	if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
+		return 0;
+
+	if (chan->flag & HOSTAPD_CHAN_DISABLED)
+		return 0;
+	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
+		return 0;
+	return 1;
+}
+
+
+static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
+{
+	/*
+	 * The tables contain first valid channel number based on channel width.
+	 * We will also choose this first channel as the control one.
+	 */
+	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			     184, 192 };
+	/*
+	 * VHT80, valid channels based on center frequency:
+	 * 42, 58, 106, 122, 138, 155
+	 */
+	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+	int *allowed = allowed_40;
+	unsigned int i, allowed_no = 0;
+
+	switch (n_chans) {
+	case 2:
+		allowed = allowed_40;
+		allowed_no = ARRAY_SIZE(allowed_40);
+		break;
+	case 4:
+		allowed = allowed_80;
+		allowed_no = ARRAY_SIZE(allowed_80);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
+		break;
+	}
+
+	for (i = 0; i < allowed_no; i++) {
+		if (chan->chan == allowed[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+				    int first_chan_idx, int num_chans,
+				    int skip_radar)
+{
+	struct hostapd_channel_data *first_chan, *chan;
+	int i;
+
+	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)
+			return 0;
+
+		if (!dfs_channel_available(chan, skip_radar))
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/*
+ * The function assumes HT40+ operation.
+ * Make sure to adjust the following variables after calling this:
+ *  - hapd->secondary_channel
+ *  - hapd->vht_oper_centr_freq_seg0_idx
+ *  - hapd->vht_oper_centr_freq_seg1_idx
+ */
+static int dfs_find_channel(struct hostapd_iface *iface,
+			    struct hostapd_channel_data **ret_chan,
+			    int idx, int skip_radar)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int i, channel_idx = 0, n_chans;
+
+	mode = iface->current_mode;
+	n_chans = dfs_get_used_n_chans(iface);
+
+	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+
+		/* Skip HT40/VHT incompatible channels */
+		if (iface->conf->ieee80211n &&
+		    iface->conf->secondary_channel &&
+		    !dfs_is_chan_allowed(chan, n_chans))
+			continue;
+
+		/* Skip incompatible chandefs */
+		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+			continue;
+
+		if (ret_chan && idx == channel_idx) {
+			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+			*ret_chan = chan;
+			return idx;
+		}
+		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+		channel_idx++;
+	}
+	return channel_idx;
+}
+
+
+static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
+				       struct hostapd_channel_data *chan,
+				       int secondary_channel,
+				       u8 *vht_oper_centr_freq_seg0_idx,
+				       u8 *vht_oper_centr_freq_seg1_idx)
+{
+	if (!iface->conf->ieee80211ac)
+		return;
+
+	if (!chan)
+		return;
+
+	*vht_oper_centr_freq_seg1_idx = 0;
+
+	switch (iface->conf->vht_oper_chwidth) {
+	case VHT_CHANWIDTH_USE_HT:
+		if (secondary_channel == 1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+		else if (secondary_channel == -1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
+		else
+			*vht_oper_centr_freq_seg0_idx = chan->chan;
+		break;
+	case VHT_CHANWIDTH_80MHZ:
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+		break;
+	case VHT_CHANWIDTH_160MHZ:
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+		break;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
+		   *vht_oper_centr_freq_seg0_idx,
+		   *vht_oper_centr_freq_seg1_idx);
+}
+
+
+/* Return start channel idx we will use for mode->channels[idx] */
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int channel_no = iface->conf->channel;
+	int res = -1, i;
+
+	/* HT40- */
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
+		channel_no -= 4;
+
+	/* VHT */
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
+		case VHT_CHANWIDTH_USE_HT:
+			break;
+		case VHT_CHANWIDTH_80MHZ:
+			channel_no =
+				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+			break;
+		case VHT_CHANWIDTH_160MHZ:
+			channel_no =
+				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
+			break;
+		default:
+			wpa_printf(MSG_INFO,
+				   "DFS only VHT20/40/80/160 is supported now");
+			channel_no = -1;
+			break;
+		}
+	}
+
+	/* Get idx */
+	mode = iface->current_mode;
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+		if (chan->chan == channel_no) {
+			res = i;
+			break;
+		}
+	}
+
+	if (res == -1)
+		wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1");
+
+	return res;
+}
+
+
+/* At least one channel have radar flag */
+static int dfs_check_chans_radar(struct hostapd_iface *iface,
+				 int start_chan_idx, int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i, res = 0;
+
+	mode = iface->current_mode;
+
+	for (i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if (channel->flag & HOSTAPD_CHAN_RADAR)
+			res++;
+	}
+
+	return res;
+}
+
+
+/* All channels available */
+static int dfs_check_chans_available(struct hostapd_iface *iface,
+				     int start_chan_idx, int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i;
+
+	mode = iface->current_mode;
+
+	for(i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
+		    HOSTAPD_CHAN_DFS_AVAILABLE)
+			break;
+	}
+
+	return i == n_chans;
+}
+
+
+/* At least one channel unavailable */
+static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
+				       int start_chan_idx,
+				       int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i, res = 0;
+
+	mode = iface->current_mode;
+
+	for(i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if (channel->flag & HOSTAPD_CHAN_DISABLED)
+			res++;
+		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
+		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
+			res++;
+	}
+
+	return res;
+}
+
+
+static struct hostapd_channel_data *
+dfs_get_valid_channel(struct hostapd_iface *iface,
+		      int *secondary_channel,
+		      u8 *vht_oper_centr_freq_seg0_idx,
+		      u8 *vht_oper_centr_freq_seg1_idx,
+		      int skip_radar)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan = NULL;
+	int num_available_chandefs;
+	int chan_idx;
+	u32 _rand;
+
+	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
+
+	if (iface->current_mode == NULL)
+		return NULL;
+
+	mode = iface->current_mode;
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return NULL;
+
+	/* Get the count first */
+	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+	if (num_available_chandefs == 0)
+		return NULL;
+
+	os_get_random((u8 *) &_rand, sizeof(_rand));
+	chan_idx = _rand % num_available_chandefs;
+	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+
+	/* dfs_find_channel() calculations assume HT40+ */
+	if (iface->conf->secondary_channel)
+		*secondary_channel = 1;
+	else
+		*secondary_channel = 0;
+
+	dfs_adjust_vht_center_freq(iface, chan,
+				   *secondary_channel,
+				   vht_oper_centr_freq_seg0_idx,
+				   vht_oper_centr_freq_seg1_idx);
+
+	return chan;
+}
+
+
+static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan = NULL;
+	int i;
+
+	mode = iface->current_mode;
+	if (mode == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
+	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		chan = &iface->current_mode->channels[i];
+		if (chan->freq == freq) {
+			if (chan->flag & HOSTAPD_CHAN_RADAR) {
+				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
+				chan->flag |= state;
+				return 1; /* Channel found */
+			}
+		}
+	}
+	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
+	return 0;
+}
+
+
+static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
+			 int chan_offset, int chan_width, int cf1,
+			 int cf2, u32 state)
+{
+	int n_chans = 1, i;
+	struct hostapd_hw_modes *mode;
+	int frequency = freq;
+	int ret = 0;
+
+	mode = iface->current_mode;
+	if (mode == NULL)
+		return 0;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
+		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
+		return 0;
+	}
+
+	/* Seems cf1 and chan_width is enough here */
+	switch (chan_width) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		n_chans = 1;
+		if (frequency == 0)
+			frequency = cf1;
+		break;
+	case CHAN_WIDTH_40:
+		n_chans = 2;
+		frequency = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		n_chans = 4;
+		frequency = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		n_chans = 8;
+		frequency = cf1 - 70;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+			   chan_width);
+		break;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
+		   n_chans);
+	for (i = 0; i < n_chans; i++) {
+		ret += set_dfs_state_freq(iface, frequency, state);
+		frequency = frequency + 20;
+	}
+
+	return ret;
+}
+
+
+static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+				       int chan_width, int cf1, int cf2)
+{
+	int start_chan_idx;
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int n_chans, i, j, frequency = freq, radar_n_chans = 1;
+	u8 radar_chan;
+	int res = 0;
+
+	/* Our configuration */
+	mode = iface->current_mode;
+	start_chan_idx = dfs_get_start_chan_idx(iface);
+	n_chans = dfs_get_used_n_chans(iface);
+
+	/* Check we are on DFS channel(s) */
+	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
+		return 0;
+
+	/* Reported via radar event */
+	switch (chan_width) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		radar_n_chans = 1;
+		if (frequency == 0)
+			frequency = cf1;
+		break;
+	case CHAN_WIDTH_40:
+		radar_n_chans = 2;
+		frequency = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		radar_n_chans = 4;
+		frequency = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		radar_n_chans = 8;
+		frequency = cf1 - 70;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+			   chan_width);
+		break;
+	}
+
+	ieee80211_freq_to_chan(frequency, &radar_chan);
+
+	for (i = 0; i < n_chans; i++) {
+		chan = &mode->channels[start_chan_idx + i];
+		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+			continue;
+		for (j = 0; j < radar_n_chans; j++) {
+			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
+				   chan->chan, radar_chan + j * 4);
+			if (chan->chan == radar_chan + j * 4)
+				res++;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
+
+	return res;
+}
+
+
+/*
+ * Main DFS handler
+ * 1 - continue channel/ap setup
+ * 0 - channel/ap setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int res, n_chans, start_chan_idx;
+	int skip_radar = 0;
+
+	iface->cac_started = 0;
+
+	do {
+		/* Get start (first) channel for current configuration */
+		start_chan_idx = dfs_get_start_chan_idx(iface);
+		if (start_chan_idx == -1)
+			return -1;
+
+		/* Get number of used channels, depend on width */
+		n_chans = dfs_get_used_n_chans(iface);
+
+		/* Check if any of configured channels require DFS */
+		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+		wpa_printf(MSG_DEBUG,
+			   "DFS %d channels required radar detection",
+			   res);
+		if (!res)
+			return 1;
+
+		/* Check if all channels are DFS available */
+		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
+		wpa_printf(MSG_DEBUG,
+			   "DFS all channels available, (SKIP CAC): %s",
+			   res ? "yes" : "no");
+		if (res)
+			return 1;
+
+		/* Check if any of configured channels is unavailable */
+		res = dfs_check_chans_unavailable(iface, start_chan_idx,
+						  n_chans);
+		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
+			   res, res ? "yes": "no");
+		if (res) {
+			int sec = 0;
+			u8 cf1 = 0, cf2 = 0;
+
+			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+							skip_radar);
+			if (!channel) {
+				wpa_printf(MSG_ERROR, "could not get valid channel");
+				return -1;
+			}
+
+			iface->freq = channel->freq;
+			iface->conf->channel = channel->chan;
+			iface->conf->secondary_channel = sec;
+			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
+			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
+		}
+	} while (res);
+
+	/* Finally start CAC */
+	hostapd_set_state(iface, HAPD_IFACE_DFS);
+	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+		"freq=%d chan=%d sec_chan=%d",
+		iface->freq,
+		iface->conf->channel, iface->conf->secondary_channel);
+	if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+				  iface->freq,
+				  iface->conf->channel,
+				  iface->conf->ieee80211n,
+				  iface->conf->ieee80211ac,
+				  iface->conf->secondary_channel,
+				  iface->conf->vht_oper_chwidth,
+				  iface->conf->vht_oper_centr_freq_seg0_idx,
+				  iface->conf->vht_oper_centr_freq_seg1_idx)) {
+		wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, 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_COMPLETED
+		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+	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);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int secondary_channel;
+	u8 vht_oper_centr_freq_seg0_idx = 0;
+	u8 vht_oper_centr_freq_seg1_idx = 0;
+	int skip_radar = 0;
+	int err = 1;
+
+	/* Radar detected during active CAC */
+	iface->cac_started = 0;
+	channel = dfs_get_valid_channel(iface, &secondary_channel,
+					&vht_oper_centr_freq_seg0_idx,
+					&vht_oper_centr_freq_seg1_idx,
+					skip_radar);
+
+	if (!channel) {
+		wpa_printf(MSG_ERROR, "No valid channel available");
+		hostapd_setup_interface_complete(iface, err);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+		   channel->chan);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+		"freq=%d chan=%d sec_chan=%d", channel->freq,
+		channel->chan, secondary_channel);
+
+	iface->freq = channel->freq;
+	iface->conf->channel = channel->chan;
+	iface->conf->secondary_channel = secondary_channel;
+	iface->conf->vht_oper_centr_freq_seg0_idx =
+		vht_oper_centr_freq_seg0_idx;
+	iface->conf->vht_oper_centr_freq_seg1_idx =
+		vht_oper_centr_freq_seg1_idx;
+	err = 0;
+
+	hostapd_setup_interface_complete(iface, err);
+	return err;
+}
+
+
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int secondary_channel;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+	int skip_radar = 1;
+	struct csa_settings csa_settings;
+	struct hostapd_data *hapd = iface->bss[0];
+	int err = 1;
+
+	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
+		   __func__, iface->cac_started ? "yes" : "no",
+		   iface->csa_in_progress ? "yes" : "no");
+
+	/* Check if CSA in progress */
+	if (iface->csa_in_progress)
+		return 0;
+
+	/* Check if active CAC */
+	if (iface->cac_started)
+		return hostapd_dfs_start_channel_switch_cac(iface);
+
+	/* Perform channel switch/CSA */
+	channel = dfs_get_valid_channel(iface, &secondary_channel,
+					&vht_oper_centr_freq_seg0_idx,
+					&vht_oper_centr_freq_seg1_idx,
+					skip_radar);
+
+	if (!channel) {
+		/* FIXME: Wait for channel(s) to become available */
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+		   channel->chan);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+		"freq=%d chan=%d sec_chan=%d", channel->freq,
+		channel->chan, secondary_channel);
+
+	/* Setup CSA request */
+	os_memset(&csa_settings, 0, sizeof(csa_settings));
+	csa_settings.cs_count = 5;
+	csa_settings.block_tx = 1;
+	err = hostapd_set_freq_params(&csa_settings.freq_params,
+				      iface->conf->hw_mode,
+				      channel->freq,
+				      channel->chan,
+				      iface->conf->ieee80211n,
+				      iface->conf->ieee80211ac,
+				      secondary_channel,
+				      iface->conf->vht_oper_chwidth,
+				      vht_oper_centr_freq_seg0_idx,
+				      vht_oper_centr_freq_seg1_idx,
+				      iface->current_mode->vht_capab);
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	err = hostapd_switch_channel(hapd, &csa_settings);
+	if (err) {
+		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
+			   err);
+		iface->freq = channel->freq;
+		iface->conf->channel = channel->chan;
+		iface->conf->secondary_channel = secondary_channel;
+		iface->conf->vht_oper_centr_freq_seg0_idx =
+			vht_oper_centr_freq_seg0_idx;
+		iface->conf->vht_oper_centr_freq_seg1_idx =
+			vht_oper_centr_freq_seg1_idx;
+
+		hostapd_disable_iface(iface);
+		hostapd_enable_iface(iface);
+		return 0;
+	}
+
+	/* Channel configuration will be updated once CSA completes and
+	 * ch_switch_notify event is received */
+
+	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
+	return 0;
+}
+
+
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+			       int ht_enabled, int chan_offset, int chan_width,
+			       int cf1, int cf2)
+{
+	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);
+
+	/* mark radar frequency as invalid */
+	res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
+			    chan_width, cf1, cf2,
+			    HOSTAPD_CHAN_DFS_UNAVAILABLE);
+
+	/* Skip if reported radar event not overlapped our channels */
+	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
+	if (!res)
+		return 0;
+
+	/* radar detected while operating, switch the channel. */
+	res = hostapd_dfs_start_channel_switch(iface);
+
+	return res;
+}
+
+
+int hostapd_dfs_nop_finished(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_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);
+	/* TODO add correct implementation here */
+	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+	return 0;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
new file mode 100644
index 0000000..859ff79
--- /dev/null
+++ b/src/ap/dfs.h
@@ -0,0 +1,25 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef DFS_H
+#define DFS_H
+
+int hostapd_handle_dfs(struct hostapd_iface *iface);
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+			     int ht_enabled, int chan_offset, int chan_width,
+			     int cf1, int cf2);
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+			       int ht_enabled,
+			       int chan_offset, int chan_width,
+			       int cf1, int cf2);
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
+			     int ht_enabled,
+			     int chan_offset, int chan_width, int cf1, int cf2);
+
+#endif /* DFS_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index d6bc98d..9af9646 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -29,6 +29,7 @@
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "hw_features.h"
+#include "dfs.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -114,6 +115,13 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+	if (elems.ext_capab && elems.ext_capab_len > 4) {
+		if (elems.ext_capab[4] & 0x01)
+			sta->qos_map_enabled = 1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
 #ifdef CONFIG_HS20
 	wpabuf_free(sta->hs20_ie);
 	if (elems.hs20 && elems.hs20_len > 4) {
@@ -291,6 +299,7 @@
 
 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
 
 	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
@@ -373,14 +382,15 @@
 
 
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset)
+			     int offset, int width, int cf1, int cf2)
 {
 #ifdef NEED_AP_MLME
-	int channel;
+	int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
-		       "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+		       "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
+		       freq, ht, offset, width, cf1, cf2);
 
 	hapd->iface->freq = freq;
 
@@ -392,9 +402,51 @@
 		return;
 	}
 
+	switch (width) {
+	case CHAN_WIDTH_80:
+		chwidth = VHT_CHANWIDTH_80MHZ;
+		break;
+	case CHAN_WIDTH_80P80:
+		chwidth = VHT_CHANWIDTH_80P80MHZ;
+		break;
+	case CHAN_WIDTH_160:
+		chwidth = VHT_CHANWIDTH_160MHZ;
+		break;
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+	case CHAN_WIDTH_40:
+	default:
+		chwidth = VHT_CHANWIDTH_USE_HT;
+		break;
+	}
+
+	switch (hapd->iface->current_mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		if (cf1 > 5000)
+			seg0_idx = (cf1 - 5000) / 5;
+		if (cf2 > 5000)
+			seg1_idx = (cf2 - 5000) / 5;
+		break;
+	default:
+		seg0_idx = hostapd_hw_get_channel(hapd, cf1);
+		seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+		break;
+	}
+
 	hapd->iconf->channel = channel;
 	hapd->iconf->ieee80211n = ht;
 	hapd->iconf->secondary_channel = offset;
+	hapd->iconf->vht_oper_chwidth = chwidth;
+	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
+	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
+
+	if (hapd->iface->csa_in_progress &&
+	    freq == hapd->iface->cs_freq_params.freq) {
+		hostapd_cleanup_cs_params(hapd);
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
+			freq);
+	}
 #endif /* NEED_AP_MLME */
 }
 
@@ -506,39 +558,48 @@
 
 
 static void hostapd_action_rx(struct hostapd_data *hapd,
-			      struct rx_action *action)
+			      struct rx_mgmt *drv_mgmt)
 {
+	struct ieee80211_mgmt *mgmt;
 	struct sta_info *sta;
+	size_t plen __maybe_unused;
+	u16 fc;
+
+	if (drv_mgmt->frame_len < 24 + 1)
+		return;
+
+	plen = drv_mgmt->frame_len - 24 - 1;
+
+	mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
+	fc = le_to_host16(mgmt->frame_control);
+	if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+		return; /* handled by the driver */
 
         wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
-		   action->category, (int) action->len);
+		   mgmt->u.action.category, (int) plen);
 
-	sta = ap_get_sta(hapd, action->sa);
+	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
 		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
 		return;
 	}
 #ifdef CONFIG_IEEE80211R
-	if (action->category == WLAN_ACTION_FT) {
-		wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
-			   __func__, (int) action->len);
-		wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+	if (mgmt->u.action.category == WLAN_ACTION_FT) {
+		const u8 *payload = drv_mgmt->frame + 24 + 1;
+		wpa_ft_action_rx(sta->wpa_sm, payload, plen);
 	}
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
-	if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
-		wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
-			   __func__, (int) action->len);
-		ieee802_11_sa_query_action(hapd, action->sa,
-					   *(action->data + 1),
-					   action->data + 2);
+	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
+		ieee802_11_sa_query_action(
+			hapd, mgmt->sa,
+			mgmt->u.action.u.sa_query_resp.action,
+			mgmt->u.action.u.sa_query_resp.trans_id);
 	}
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM
-	if (action->category == WLAN_ACTION_WNM) {
-		wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
-			   __func__, (int) action->len);
-		ieee802_11_rx_wnm_action_ap(hapd, action);
+	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
+		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
 	}
 #endif /* CONFIG_WNM */
 }
@@ -580,17 +641,18 @@
 }
 
 
-static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
+static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
 {
 	struct hostapd_iface *iface = hapd->iface;
 	const struct ieee80211_hdr *hdr;
 	const u8 *bssid;
 	struct hostapd_frame_info fi;
+	int ret;
 
 	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
 	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
 	if (bssid == NULL)
-		return;
+		return 0;
 
 	hapd = get_hapd_bssid(iface, bssid);
 	if (hapd == NULL) {
@@ -605,7 +667,7 @@
 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
 			hapd = iface->bss[0];
 		else
-			return;
+			return 0;
 	}
 
 	os_memset(&fi, 0, sizeof(fi));
@@ -614,53 +676,19 @@
 
 	if (hapd == HAPD_BROADCAST) {
 		size_t i;
-		for (i = 0; i < iface->num_bss; i++)
-			ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
-					rx_mgmt->frame_len, &fi);
+		ret = 0;
+		for (i = 0; i < iface->num_bss; i++) {
+			if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
+					    rx_mgmt->frame_len, &fi) > 0)
+				ret = 1;
+		}
 	} else
-		ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
+		ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
+				      &fi);
 
 	random_add_randomness(&fi, sizeof(fi));
-}
 
-
-static void hostapd_rx_action(struct hostapd_data *hapd,
-			      struct rx_action *rx_action)
-{
-	struct rx_mgmt rx_mgmt;
-	u8 *buf;
-	struct ieee80211_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
-		   " BSSID=" MACSTR " category=%u",
-		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
-		   MAC2STR(rx_action->bssid), rx_action->category);
-	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
-		    rx_action->data, rx_action->len);
-
-	buf = os_zalloc(24 + 1 + rx_action->len);
-	if (buf == NULL)
-		return;
-	hdr = (struct ieee80211_hdr *) buf;
-	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
-		/*
-		 * Assume frame was protected; it would have been dropped if
-		 * not.
-		 */
-		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-	}
-	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
-	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
-	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
-	buf[24] = rx_action->category;
-	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
-	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
-	rx_mgmt.frame = buf;
-	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
-	hostapd_mgmt_rx(hapd, &rx_mgmt);
-	os_free(buf);
+	return ret;
 }
 
 
@@ -785,6 +813,50 @@
 }
 
 
+#ifdef NEED_AP_MLME
+
+static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
+					     struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
+	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
+				   radar->chan_offset, radar->chan_width,
+				   radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
+					   struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
+					  struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
+	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
+					   struct dfs_event *radar)
+{
+	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
+	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
+				 radar->chan_offset, radar->chan_width,
+				 radar->cf1, radar->cf2);
+}
+
+#endif /* NEED_AP_MLME */
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -858,10 +930,14 @@
 					    data->rx_from_unknown.addr,
 					    data->rx_from_unknown.wds);
 		break;
-	case EVENT_RX_MGMT:
-		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
-		break;
 #endif /* NEED_AP_MLME */
+	case EVENT_RX_MGMT:
+#ifdef NEED_AP_MLME
+		if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
+			break;
+#endif /* NEED_AP_MLME */
+		hostapd_action_rx(hapd, &data->rx_mgmt);
+		break;
 	case EVENT_RX_PROBE_REQ:
 		if (data->rx_probe_req.sa == NULL ||
 		    data->rx_probe_req.ie == NULL)
@@ -900,15 +976,6 @@
 			break;
 		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
 		break;
-	case EVENT_RX_ACTION:
-		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
-		    data->rx_action.bssid == NULL)
-			break;
-#ifdef NEED_AP_MLME
-		hostapd_rx_action(hapd, &data->rx_action);
-#endif /* NEED_AP_MLME */
-		hostapd_action_rx(hapd, &data->rx_action);
-		break;
 	case EVENT_AUTH:
 		hostapd_notif_auth(hapd, &data->auth);
 		break;
@@ -917,7 +984,10 @@
 			break;
 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
 					data->ch_switch.ht_enabled,
-					data->ch_switch.ch_offset);
+					data->ch_switch.ch_offset,
+					data->ch_switch.ch_width,
+					data->ch_switch.cf1,
+					data->ch_switch.cf2);
 		break;
 	case EVENT_CONNECT_FAILED_REASON:
 		if (!data)
@@ -929,6 +999,36 @@
 	case EVENT_SURVEY:
 		hostapd_event_get_survey(hapd, &data->survey_results);
 		break;
+#ifdef NEED_AP_MLME
+	case EVENT_DFS_RADAR_DETECTED:
+		if (!data)
+			break;
+		hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_FINISHED:
+		if (!data)
+			break;
+		hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_CAC_ABORTED:
+		if (!data)
+			break;
+		hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
+		break;
+	case EVENT_DFS_NOP_FINISHED:
+		if (!data)
+			break;
+		hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
+		break;
+	case EVENT_CHANNEL_LIST_CHANGED:
+		/* channel list changed (regulatory?), update channel list */
+		/* TODO: check this. hostapd_get_hw_features() initializes
+		 * too much stuff. */
+		/* hostapd_get_hw_features(hapd->iface); */
+		hostapd_channel_list_updated(
+			hapd->iface, data->channel_list_changed.initiator);
+		break;
+#endif /* NEED_AP_MLME */
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index b3574ba..b5fb7df 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1,6 +1,6 @@
 /*
  * Generic advertisement service (GAS) server
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,6 +19,13 @@
 #include "gas_serv.h"
 
 
+static void convert_to_protected_dual(struct wpabuf *msg)
+{
+	u8 *categ = wpabuf_mhead_u8(msg);
+	*categ = WLAN_ACTION_PROTECTED_DUAL;
+}
+
+
 static struct gas_dialog_info *
 gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
 {
@@ -46,6 +53,8 @@
 		 * it to be that long.
 		 */
 		ap_sta_session_timeout(hapd, sta, 5);
+	} else {
+		ap_sta_replenish_timeout(hapd, sta, 5);
 	}
 
 	if (sta->gas_dialog == NULL) {
@@ -772,7 +781,7 @@
 
 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
 					  const u8 *sa, u8 dialog_token,
-					  struct anqp_query_info *qi)
+					  struct anqp_query_info *qi, int prot)
 {
 	struct wpabuf *buf, *tx_buf;
 
@@ -804,6 +813,7 @@
 			wpabuf_free(buf);
 			return;
 		}
+		di->prot = prot;
 		di->sd_resp = buf;
 		di->sd_resp_pos = 0;
 		tx_buf = gas_anqp_build_initial_resp_buf(
@@ -817,7 +827,8 @@
 	}
 	if (!tx_buf)
 		return;
-
+	if (prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -826,7 +837,7 @@
 
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
 					const u8 *sa,
-					const u8 *data, size_t len)
+					const u8 *data, size_t len, int prot)
 {
 	const u8 *pos = data;
 	const u8 *end = data + len;
@@ -876,6 +887,8 @@
 			return;
 		wpabuf_put_data(buf, adv_proto, 2 + slen);
 		wpabuf_put_le16(buf, 0); /* Query Response Length */
+		if (prot)
+			convert_to_protected_dual(buf);
 		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 					wpabuf_head(buf), wpabuf_len(buf));
 		wpabuf_free(buf);
@@ -927,7 +940,7 @@
 		pos += elen;
 	}
 
-	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
 }
 
 
@@ -973,6 +986,8 @@
 		if (tx_buf) {
 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
+			if (dialog->prot)
+				convert_to_protected_dual(tx_buf);
 			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
 						dst,
 						wpabuf_head(tx_buf),
@@ -1010,6 +1025,8 @@
 		dialog->sd_frag_id, (int) frag_len);
 	dialog->sd_frag_id++;
 
+	if (dialog->prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -1020,7 +1037,7 @@
 
 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
 					 const u8 *sa,
-					 const u8 *data, size_t len)
+					 const u8 *data, size_t len, int prot)
 {
 	struct gas_dialog_info *dialog;
 	struct wpabuf *buf, *tx_buf;
@@ -1118,6 +1135,8 @@
 	}
 
 send_resp:
+	if (prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -1135,22 +1154,30 @@
 	const struct ieee80211_mgmt *mgmt;
 	size_t hdr_len;
 	const u8 *sa, *data;
+	int prot;
 
 	mgmt = (const struct ieee80211_mgmt *) buf;
 	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
 	if (hdr_len > len)
 		return;
-	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+	    mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
 		return;
+	/*
+	 * Note: Public Action and Protected Dual of Public Action frames share
+	 * the same payload structure, so it is fine to use definitions of
+	 * Public Action frames to process both.
+	 */
+	prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
 	sa = mgmt->sa;
 	len -= hdr_len;
 	data = &mgmt->u.action.u.public_action.action;
 	switch (data[0]) {
 	case WLAN_PA_GAS_INITIAL_REQ:
-		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
 		break;
 	case WLAN_PA_GAS_COMEBACK_REQ:
-		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
 		break;
 	}
 }
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 4213cf6..74739fe 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -50,6 +50,7 @@
 	size_t sd_resp_pos; /* Offset in sd_resp */
 	u8 sd_frag_id;
 	u16 comeback_delay;
+	int prot; /* whether Protected Dual of Public Action frame is used */
 
 	unsigned int requested;
 	unsigned int received;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index fd1ca2b..98148da 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,9 +11,9 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "radius/radius_client.h"
 #include "radius/radius_das.h"
-#include "drivers/driver.h"
 #include "hostapd.h"
 #include "authsrv.h"
 #include "sta_info.h"
@@ -32,14 +32,14 @@
 #include "ap_config.h"
 #include "p2p_hostapd.h"
 #include "gas_serv.h"
+#include "dfs.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
-
-extern int wpa_debug_level;
-extern struct wpa_driver_ops *wpa_drivers[];
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
 
 
 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -61,10 +61,22 @@
 
 static void hostapd_reload_bss(struct hostapd_data *hapd)
 {
+	struct hostapd_ssid *ssid;
+
 #ifndef CONFIG_NO_RADIUS
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
 
+	ssid = &hapd->conf->ssid;
+	if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+	    ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+		/*
+		 * Force PSK to be derived again since SSID or passphrase may
+		 * have changed.
+		 */
+		os_free(ssid->wpa_psk);
+		ssid->wpa_psk = NULL;
+	}
 	if (hostapd_setup_wpa_psk(hapd->conf)) {
 		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
 			   "after reloading configuration");
@@ -159,7 +171,7 @@
 	for (j = 0; j < iface->num_bss; j++) {
 		hapd = iface->bss[j];
 		hapd->iconf = newconf;
-		hapd->conf = &newconf->bss[j];
+		hapd->conf = newconf->bss[j];
 		hostapd_reload_bss(hapd);
 	}
 
@@ -227,6 +239,14 @@
 
 static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
+	if (!hapd->started) {
+		wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
+			   __func__, hapd->conf->iface);
+		return;
+	}
+	hapd->started = 0;
+
+	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
 	iapp_deinit(hapd->iapp);
 	hapd->iapp = NULL;
 	accounting_deinit(hapd);
@@ -278,13 +298,13 @@
  * @hapd: Pointer to BSS data
  *
  * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
+ * Most of the modules that are initialized in hostapd_setup_bss() are
+ * deinitialized here.
  */
 static void hostapd_cleanup(struct hostapd_data *hapd)
 {
+	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
+		   hapd->conf->iface);
 	if (hapd->iface->interfaces &&
 	    hapd->iface->interfaces->ctrl_iface_deinit)
 		hapd->iface->interfaces->ctrl_iface_deinit(hapd);
@@ -292,20 +312,9 @@
 }
 
 
-/**
- * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
- * @iface: Pointer to interface data
- *
- * This function is called before per-BSS data structures are deinitialized
- * with hostapd_cleanup().
- */
-static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
-{
-}
-
-
 static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
@@ -325,12 +334,16 @@
  */
 static void hostapd_cleanup_iface(struct hostapd_iface *iface)
 {
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
 	hostapd_cleanup_iface_partial(iface);
 	hostapd_config_free(iface->conf);
 	iface->conf = NULL;
 
 	os_free(iface->config_fname);
 	os_free(iface->bss);
+	wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
 	os_free(iface);
 }
 
@@ -429,7 +442,7 @@
 	/* Determine the bits necessary to any configured BSSIDs,
 	   if they are higher than the number of BSSIDs. */
 	for (j = 0; j < iface->conf->num_bss; j++) {
-		if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
+		if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
 			if (j)
 				auto_addr++;
 			continue;
@@ -437,7 +450,7 @@
 
 		for (i = 0; i < ETH_ALEN; i++) {
 			mask[i] |=
-				iface->conf->bss[j].bssid[i] ^
+				iface->conf->bss[j]->bssid[i] ^
 				hapd->own_addr[i];
 		}
 	}
@@ -502,7 +515,7 @@
 	size_t i;
 
 	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+		if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
 			return 1;
 		}
 	}
@@ -516,7 +529,34 @@
 static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
 				    struct radius_das_attrs *attr)
 {
-	/* TODO */
+	if (attr->nas_identifier &&
+	    (!hapd->conf->nas_identifier ||
+	     os_strlen(hapd->conf->nas_identifier) !=
+	     attr->nas_identifier_len ||
+	     os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier,
+		       attr->nas_identifier_len) != 0)) {
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch");
+		return 1;
+	}
+
+	if (attr->nas_ip_addr &&
+	    (hapd->conf->own_ip_addr.af != AF_INET ||
+	     os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) !=
+	     0)) {
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch");
+		return 1;
+	}
+
+#ifdef CONFIG_IPV6
+	if (attr->nas_ipv6_addr &&
+	    (hapd->conf->own_ip_addr.af != AF_INET6 ||
+	     os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16)
+	     != 0)) {
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch");
+		return 1;
+	}
+#endif /* CONFIG_IPV6 */
+
 	return 0;
 }
 
@@ -583,6 +623,8 @@
 	if (sta == NULL)
 		return RADIUS_DAS_SESSION_NOT_FOUND;
 
+	wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+
 	hostapd_drv_sta_deauth(hapd, sta->addr,
 			       WLAN_REASON_PREV_AUTH_NOT_VALID);
 	ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -596,7 +638,8 @@
 /**
  * hostapd_setup_bss - Per-BSS setup (initialization)
  * @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ *	but interface may exist
  *
  * This function is used to initialize all per-BSS data structures and
  * resources. This gets called in a loop for each BSS when an interface is
@@ -611,7 +654,17 @@
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
 
-	if (!first) {
+	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
+		   __func__, hapd, hapd->conf->iface, first);
+
+	if (hapd->started) {
+		wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
+			   __func__, hapd->conf->iface);
+		return -1;
+	}
+	hapd->started = 1;
+
+	if (!first || first == -1) {
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
 			/* Allocate the next available BSSID. */
 			do {
@@ -636,9 +689,10 @@
 				   hapd->conf->iface, hapd->own_addr, hapd,
 				   &hapd->drv_priv, force_ifname, if_addr,
 				   hapd->conf->bridge[0] ? hapd->conf->bridge :
-				   NULL)) {
+				   NULL, first == -1)) {
 			wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
 				   MACSTR ")", MAC2STR(hapd->own_addr));
+			hapd->interface_added = 0;
 			return -1;
 		}
 	}
@@ -768,22 +822,22 @@
 		wpa_printf(MSG_ERROR, "GAS server initialization failed");
 		return -1;
 	}
-#endif /* CONFIG_INTERWORKING */
 
-	if (hapd->iface->interfaces &&
-	    hapd->iface->interfaces->ctrl_iface_init &&
-	    hapd->iface->interfaces->ctrl_iface_init(hapd)) {
-		wpa_printf(MSG_ERROR, "Failed to setup control interface");
+	if (conf->qos_map_set_len &&
+	    hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+				    conf->qos_map_set_len)) {
+		wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
 		return -1;
 	}
+#endif /* CONFIG_INTERWORKING */
 
 	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
 		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
 		return -1;
 	}
 
-	if (!hapd->conf->start_disabled)
-		ieee802_11_set_beacon(hapd);
+	if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+		return -1;
 
 	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
 		return -1;
@@ -849,14 +903,15 @@
 
 	if (hapd->iface->drv_max_acl_mac_addrs == 0)
 		return;
-	if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+	if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
 		return;
 
-	if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
-		if (conf->bss->num_accept_mac) {
+	if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+		if (conf->bss[0]->num_accept_mac) {
 			accept_acl = 1;
-			err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
-						   conf->bss->num_accept_mac,
+			err = hostapd_set_acl_list(hapd,
+						   conf->bss[0]->accept_mac,
+						   conf->bss[0]->num_accept_mac,
 						   accept_acl);
 			if (err) {
 				wpa_printf(MSG_DEBUG, "Failed to set accept acl");
@@ -865,11 +920,11 @@
 		} else {
 			wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
 		}
-	} else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
-		if (conf->bss->num_deny_mac) {
+	} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+		if (conf->bss[0]->num_deny_mac) {
 			accept_acl = 0;
-			err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
-						   conf->bss->num_deny_mac,
+			err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+						   conf->bss[0]->num_deny_mac,
 						   accept_acl);
 			if (err) {
 				wpa_printf(MSG_DEBUG, "Failed to set deny acl");
@@ -882,11 +937,85 @@
 }
 
 
+static int start_ctrl_iface_bss(struct hostapd_data *hapd)
+{
+	if (!hapd->iface->interfaces ||
+	    !hapd->iface->interfaces->ctrl_iface_init)
+		return 0;
+
+	if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to setup control interface for %s",
+			   hapd->conf->iface);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int start_ctrl_iface(struct hostapd_iface *iface)
+{
+	size_t i;
+
+	if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
+		return 0;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *hapd = iface->bss[i];
+		if (iface->interfaces->ctrl_iface_init(hapd)) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to setup control interface for %s",
+				   hapd->conf->iface);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+
+	if (!iface->wait_channel_update) {
+		wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+		return;
+	}
+
+	/*
+	 * It is possible that the existing channel list is acceptable, so try
+	 * to proceed.
+	 */
+	wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+	setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
+{
+	if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+	setup_interface2(iface);
+}
+
+
 static int setup_interface(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
 	size_t i;
-	char country[4];
+
+	if (!iface->phy[0]) {
+		const char *phy = hostapd_drv_get_radio_name(hapd);
+		if (phy) {
+			wpa_printf(MSG_DEBUG, "phy: %s", phy);
+			os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+		}
+	}
 
 	/*
 	 * Make sure that all BSSes get configured with a pointer to the same
@@ -900,15 +1029,49 @@
 	if (hostapd_validate_bssid_configuration(iface))
 		return -1;
 
+	/*
+	 * Initialize control interfaces early to allow external monitoring of
+	 * channel setup operations that may take considerable amount of time
+	 * especially for DFS cases.
+	 */
+	if (start_ctrl_iface(iface))
+		return -1;
+
 	if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+		char country[4], previous_country[4];
+
+		hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
+		if (hostapd_get_country(hapd, previous_country) < 0)
+			previous_country[0] = '\0';
+
 		os_memcpy(country, hapd->iconf->country, 3);
 		country[3] = '\0';
 		if (hostapd_set_country(hapd, country) < 0) {
 			wpa_printf(MSG_ERROR, "Failed to set country code");
 			return -1;
 		}
+
+		wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+			   previous_country, country);
+
+		if (os_strncmp(previous_country, country, 2) != 0) {
+			wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+			iface->wait_channel_update = 1;
+			eloop_register_timeout(5, 0,
+					       channel_list_update_timeout,
+					       iface, NULL);
+			return 0;
+		}
 	}
 
+	return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+	iface->wait_channel_update = 0;
+
 	if (hostapd_get_hw_features(iface)) {
 		/* Not all drivers support this yet, so continue without hw
 		 * feature data. */
@@ -931,11 +1094,22 @@
 				   "be completed in a callback");
 			return 0;
 		}
+
+		if (iface->conf->ieee80211h)
+			wpa_printf(MSG_DEBUG, "DFS support is enabled");
 	}
 	return hostapd_setup_interface_complete(iface, 0);
 }
 
 
+/**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 {
 	struct hostapd_data *hapd = iface->bss[0];
@@ -944,17 +1118,30 @@
 
 	if (err) {
 		wpa_printf(MSG_ERROR, "Interface initialization failed");
-		eloop_terminate();
+		hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+		if (iface->interfaces && iface->interfaces->terminate_on_error)
+			eloop_terminate();
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
-	if (hapd->iconf->channel) {
-		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+	if (iface->conf->channel) {
+#ifdef NEED_AP_MLME
+		int res;
+#endif /* NEED_AP_MLME */
+
+		iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
 		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
 			   "Frequency: %d MHz",
-			   hostapd_hw_mode_txt(hapd->iconf->hw_mode),
-			   hapd->iconf->channel, iface->freq);
+			   hostapd_hw_mode_txt(iface->conf->hw_mode),
+			   iface->conf->channel, iface->freq);
+
+#ifdef NEED_AP_MLME
+		/* Check DFS */
+		res = hostapd_handle_dfs(iface);
+		if (res <= 0)
+			return res;
+#endif /* NEED_AP_MLME */
 
 		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
 				     hapd->iconf->channel,
@@ -1006,6 +1193,7 @@
 		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
 			prev_addr = hapd->own_addr;
 	}
+	hapd = iface->bss[0];
 
 	hostapd_tx_queue_params(iface);
 
@@ -1030,11 +1218,15 @@
 			return -1;
 	}
 
+	hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
 	if (hapd->setup_complete_cb)
 		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
 
 	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
 		   iface->bss[0]->conf->iface);
+	if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
+		iface->interfaces->terminate_on_error--;
 
 	return 0;
 }
@@ -1049,6 +1241,12 @@
  * and sets driver parameters based on the configuration.
  * Flushes old stations, sets the channel, encryption,
  * beacons, and WDS links based on the configuration.
+ *
+ * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
+ * or DFS operations, this function returns 0 before such operations have been
+ * completed. The pending operations are registered into eloop and will be
+ * completed from eloop callbacks. Those callbacks end up calling
+ * hostapd_setup_interface_complete() once setup has been completed.
  */
 int hostapd_setup_interface(struct hostapd_iface *iface)
 {
@@ -1098,44 +1296,259 @@
 }
 
 
+static void hostapd_bss_deinit(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
+		   hapd->conf->iface);
+	hostapd_free_stas(hapd);
+	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+	hostapd_clear_wep(hapd);
+	hostapd_cleanup(hapd);
+}
+
+
 void hostapd_interface_deinit(struct hostapd_iface *iface)
 {
-	size_t j;
+	int j;
 
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	if (iface == NULL)
 		return;
 
-	hostapd_cleanup_iface_pre(iface);
-	for (j = 0; j < iface->num_bss; j++) {
-		struct hostapd_data *hapd = iface->bss[j];
-		hostapd_free_stas(hapd);
-		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
-		hostapd_clear_wep(hapd);
-		hostapd_cleanup(hapd);
-	}
+	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+	iface->wait_channel_update = 0;
+
+	for (j = iface->num_bss - 1; j >= 0; j--)
+		hostapd_bss_deinit(iface->bss[j]);
 }
 
 
 void hostapd_interface_free(struct hostapd_iface *iface)
 {
 	size_t j;
-	for (j = 0; j < iface->num_bss; j++)
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+	for (j = 0; j < iface->num_bss; j++) {
+		wpa_printf(MSG_DEBUG, "%s: free hapd %p",
+			   __func__, iface->bss[j]);
 		os_free(iface->bss[j]);
+	}
 	hostapd_cleanup_iface(iface);
 }
 
 
-#ifdef HOSTAPD
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+				    const char *config_file)
+{
+	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_config *conf = NULL;
+	struct hostapd_data *hapd;
+	size_t i;
+
+	hapd_iface = os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL)
+		goto fail;
+
+	hapd_iface->config_fname = os_strdup(config_file);
+	if (hapd_iface->config_fname == NULL)
+		goto fail;
+
+	conf = interfaces->config_read_cb(hapd_iface->config_fname);
+	if (conf == NULL)
+		goto fail;
+	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)
+		goto fail;
+
+	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)
+			goto fail;
+		hapd->msg_ctx = hapd;
+	}
+
+	return hapd_iface;
+
+fail:
+	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+		   config_file);
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->config_fname);
+		os_free(hapd_iface->bss);
+		wpa_printf(MSG_DEBUG, "%s: free iface %p",
+			   __func__, hapd_iface);
+		os_free(hapd_iface);
+	}
+	return NULL;
+}
+
+
+static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
+{
+	size_t i, j;
+
+	for (i = 0; i < interfaces->count; i++) {
+		struct hostapd_iface *iface = interfaces->iface[i];
+		for (j = 0; j < iface->num_bss; j++) {
+			struct hostapd_data *hapd = iface->bss[j];
+			if (os_strcmp(ifname, hapd->conf->iface) == 0)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * hostapd_interface_init_bss - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a BSS. This BSS is
+ * added to an existing interface sharing the same radio (if any) or a new
+ * interface is created if this is the first interface on a radio. This
+ * allocate memory for the BSS. No actual driver operations are started.
+ *
+ * This is similar to hostapd_interface_init(), but for a case where the
+ * configuration is used to add a single BSS instead of all BSSes for a radio.
+ */
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+			   const char *config_fname, int debug)
+{
+	struct hostapd_iface *new_iface = NULL, *iface = NULL;
+	struct hostapd_data *hapd;
+	int k;
+	size_t i, bss_idx;
+
+	if (!phy || !*phy)
+		return NULL;
+
+	for (i = 0; i < interfaces->count; i++) {
+		if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+			iface = interfaces->iface[i];
+			break;
+		}
+	}
+
+	wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
+		   config_fname, phy, iface ? "" : " --> new PHY");
+	if (iface) {
+		struct hostapd_config *conf;
+		struct hostapd_bss_config **tmp_conf;
+		struct hostapd_data **tmp_bss;
+		struct hostapd_bss_config *bss;
+		const char *ifname;
+
+		/* Add new BSS to existing iface */
+		conf = interfaces->config_read_cb(config_fname);
+		if (conf == NULL)
+			return NULL;
+		if (conf->num_bss > 1) {
+			wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+			hostapd_config_free(conf);
+			return NULL;
+		}
+
+		ifname = conf->bss[0]->iface;
+		if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
+			wpa_printf(MSG_ERROR,
+				   "Interface name %s already in use", ifname);
+			hostapd_config_free(conf);
+			return NULL;
+		}
+
+		tmp_conf = os_realloc_array(
+			iface->conf->bss, iface->conf->num_bss + 1,
+			sizeof(struct hostapd_bss_config *));
+		tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+					   sizeof(struct hostapd_data *));
+		if (tmp_bss)
+			iface->bss = tmp_bss;
+		if (tmp_conf) {
+			iface->conf->bss = tmp_conf;
+			iface->conf->last_bss = tmp_conf[0];
+		}
+		if (tmp_bss == NULL || tmp_conf == NULL) {
+			hostapd_config_free(conf);
+			return NULL;
+		}
+		bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+		iface->conf->num_bss++;
+
+		hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+		if (hapd == NULL) {
+			iface->conf->num_bss--;
+			hostapd_config_free(conf);
+			return NULL;
+		}
+		iface->conf->last_bss = bss;
+		iface->bss[iface->num_bss] = hapd;
+		hapd->msg_ctx = hapd;
+
+		bss_idx = iface->num_bss++;
+		conf->num_bss--;
+		conf->bss[0] = NULL;
+		hostapd_config_free(conf);
+	} else {
+		/* Add a new iface with the first BSS */
+		new_iface = iface = hostapd_init(interfaces, config_fname);
+		if (!iface)
+			return NULL;
+		os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+		iface->interfaces = interfaces;
+		bss_idx = 0;
+	}
+
+	for (k = 0; k < debug; k++) {
+		if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+			iface->bss[bss_idx]->conf->logger_stdout_level--;
+	}
+
+	if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+	    !hostapd_drv_none(iface->bss[bss_idx])) {
+		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+			   config_fname);
+		if (new_iface)
+			hostapd_interface_deinit_free(new_iface);
+		return NULL;
+	}
+
+	return iface;
+}
+
 
 void hostapd_interface_deinit_free(struct hostapd_iface *iface)
 {
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
+
+	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	if (iface == NULL)
 		return;
+	wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
+		   __func__, (unsigned int) iface->num_bss,
+		   (unsigned int) iface->conf->num_bss);
 	driver = iface->bss[0]->driver;
 	drv_priv = iface->bss[0]->drv_priv;
 	hostapd_interface_deinit(iface);
+	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv)
 		driver->hapd_deinit(drv_priv);
 	hostapd_interface_free(iface);
@@ -1146,20 +1559,38 @@
 {
 	if (hapd_iface->bss[0]->drv_priv != NULL) {
 		wpa_printf(MSG_ERROR, "Interface %s already enabled",
-			   hapd_iface->conf->bss[0].iface);
+			   hapd_iface->conf->bss[0]->iface);
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "Enable interface %s",
-		   hapd_iface->conf->bss[0].iface);
+		   hapd_iface->conf->bss[0]->iface);
+
+	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
+		wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
+		return -1;
+	}
 
 	if (hapd_iface->interfaces == NULL ||
 	    hapd_iface->interfaces->driver_init == NULL ||
-	    hapd_iface->interfaces->driver_init(hapd_iface) ||
-	    hostapd_setup_interface(hapd_iface)) {
-		hostapd_interface_deinit_free(hapd_iface);
+	    hapd_iface->interfaces->driver_init(hapd_iface))
+		return -1;
+
+	if (hostapd_setup_interface(hapd_iface)) {
+		const struct wpa_driver_ops *driver;
+		void *drv_priv;
+
+		driver = hapd_iface->bss[0]->driver;
+		drv_priv = hapd_iface->bss[0]->drv_priv;
+		wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+			   __func__, driver, drv_priv);
+		if (driver && driver->hapd_deinit && drv_priv) {
+			driver->hapd_deinit(drv_priv);
+			hapd_iface->bss[0]->drv_priv = NULL;
+		}
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -1169,19 +1600,17 @@
 	size_t j;
 
 	wpa_printf(MSG_DEBUG, "Reload interface %s",
-		   hapd_iface->conf->bss[0].iface);
-	for (j = 0; j < hapd_iface->num_bss; j++) {
-		hostapd_flush_old_stations(hapd_iface->bss[j],
-					   WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-#ifndef CONFIG_NO_RADIUS
-		/* TODO: update dynamic data based on changed configuration
-		 * items (e.g., open/close sockets, etc.) */
-		radius_client_flush(hapd_iface->bss[j]->radius, 0);
-#endif  /* CONFIG_NO_RADIUS */
-
-		hostapd_reload_bss(hapd_iface->bss[j]);
+		   hapd_iface->conf->bss[0]->iface);
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_set_security_params(hapd_iface->conf->bss[j]);
+	if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
+		wpa_printf(MSG_ERROR, "Updated configuration is invalid");
+		return -1;
 	}
+	hostapd_clear_old(hapd_iface);
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_reload_bss(hapd_iface->bss[j]);
+
 	return 0;
 }
 
@@ -1189,13 +1618,12 @@
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
 {
 	size_t j;
-	struct hostapd_bss_config *bss;
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
 
 	if (hapd_iface == NULL)
 		return -1;
-	bss = hapd_iface->bss[0]->conf;
+	wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
 	driver = hapd_iface->bss[0]->driver;
 	drv_priv = hapd_iface->bss[0]->drv_priv;
 
@@ -1208,6 +1636,8 @@
 		hostapd_free_hapd_data(hapd);
 	}
 
+	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv) {
 		driver->hapd_deinit(drv_priv);
 		hapd_iface->bss[0]->drv_priv = NULL;
@@ -1217,11 +1647,10 @@
 	 * hostapd_setup_interface and hostapd_setup_interface_complete
 	 */
 	hostapd_cleanup_iface_partial(hapd_iface);
-	bss->wpa = 0;
-	bss->wpa_key_mgmt = -1;
-	bss->wpa_pairwise = -1;
 
-	wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+	wpa_printf(MSG_DEBUG, "Interface %s disabled",
+		   hapd_iface->bss[0]->conf->iface);
+	hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
 	return 0;
 }
 
@@ -1272,7 +1701,7 @@
 		return NULL;
 	}
 
-	bss = conf->last_bss = conf->bss;
+	bss = conf->last_bss = conf->bss[0];
 
 	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
 	bss->ctrl_interface = os_strdup(ctrl_iface);
@@ -1307,8 +1736,7 @@
 
 	for (i = 0; i < conf->num_bss; i++) {
 		hapd = hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
+			hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
 		if (hapd == NULL)
 			return NULL;
 		hapd->msg_ctx = hapd;
@@ -1323,17 +1751,83 @@
 int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
 {
 	struct hostapd_config *conf = NULL;
-	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
+	struct hostapd_data *hapd;
 	char *ptr;
-	size_t i;
+	size_t i, j;
+	const char *conf_file = NULL, *phy_name = NULL;
+
+	if (os_strncmp(buf, "bss_config=", 11) == 0) {
+		char *pos;
+		phy_name = buf + 11;
+		pos = os_strchr(phy_name, ':');
+		if (!pos)
+			return -1;
+		*pos++ = '\0';
+		conf_file = pos;
+		if (!os_strlen(conf_file))
+			return -1;
+
+		hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
+							conf_file, 0);
+		if (!hapd_iface)
+			return -1;
+		for (j = 0; j < interfaces->count; j++) {
+			if (interfaces->iface[j] == hapd_iface)
+				break;
+		}
+		if (j == interfaces->count) {
+			struct hostapd_iface **tmp;
+			tmp = os_realloc_array(interfaces->iface,
+					       interfaces->count + 1,
+					       sizeof(struct hostapd_iface *));
+			if (!tmp) {
+				hostapd_interface_deinit_free(hapd_iface);
+				return -1;
+			}
+			interfaces->iface = tmp;
+			interfaces->iface[interfaces->count++] = hapd_iface;
+			new_iface = hapd_iface;
+		}
+
+		if (new_iface) {
+			if (interfaces->driver_init(hapd_iface) ||
+			    hostapd_setup_interface(hapd_iface)) {
+				interfaces->count--;
+				goto fail;
+			}
+		} else {
+			/* Assign new BSS with bss[0]'s driver info */
+			hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
+			hapd->driver = hapd_iface->bss[0]->driver;
+			hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
+			os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
+				  ETH_ALEN);
+
+			if (start_ctrl_iface_bss(hapd) < 0 ||
+			    (hapd_iface->state == HAPD_IFACE_ENABLED &&
+			     hostapd_setup_bss(hapd, -1))) {
+				hapd_iface->conf->num_bss--;
+				hapd_iface->num_bss--;
+				wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
+					   __func__, hapd, hapd->conf->iface);
+				os_free(hapd);
+				return -1;
+			}
+		}
+		return 0;
+	}
 
 	ptr = os_strchr(buf, ' ');
 	if (ptr == NULL)
 		return -1;
 	*ptr++ = '\0';
 
+	if (os_strncmp(ptr, "config=", 7) == 0)
+		conf_file = ptr + 7;
+
 	for (i = 0; i < interfaces->count; i++) {
-		if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+		if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
 			       buf)) {
 			wpa_printf(MSG_INFO, "Cannot add interface - it "
 				   "already exists");
@@ -1348,8 +1842,14 @@
 		goto fail;
 	}
 
-	conf = hostapd_config_alloc(interfaces, buf, ptr);
-	if (conf == NULL) {
+	if (conf_file && interfaces->config_read_cb) {
+		conf = interfaces->config_read_cb(conf_file);
+		if (conf && conf->bss)
+			os_strlcpy(conf->bss[0]->iface, buf,
+				   sizeof(conf->bss[0]->iface));
+	} else
+		conf = hostapd_config_alloc(interfaces, buf, ptr);
+	if (conf == NULL || conf->bss == NULL) {
 		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
 			   "for configuration", __func__);
 		goto fail;
@@ -1362,14 +1862,10 @@
 		goto fail;
 	}
 
-	if (hapd_iface->interfaces &&
-	    hapd_iface->interfaces->ctrl_iface_init &&
-	    hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
-		wpa_printf(MSG_ERROR, "%s: Failed to setup control "
-			   "interface", __func__);
+	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'", conf->bss[0]->iface);
 
 	return 0;
 
@@ -1377,23 +1873,71 @@
 	if (conf)
 		hostapd_config_free(conf);
 	if (hapd_iface) {
-		os_free(hapd_iface->bss[interfaces->count]);
+		if (hapd_iface->bss) {
+			for (i = 0; i < hapd_iface->num_bss; i++) {
+				hapd = hapd_iface->bss[i];
+				if (hapd && hapd_iface->interfaces &&
+				    hapd_iface->interfaces->ctrl_iface_deinit)
+					hapd_iface->interfaces->
+						ctrl_iface_deinit(hapd);
+				wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+					   __func__, hapd_iface->bss[i],
+					hapd_iface->bss[i]->conf->iface);
+				os_free(hapd_iface->bss[i]);
+			}
+			os_free(hapd_iface->bss);
+		}
+		wpa_printf(MSG_DEBUG, "%s: free iface %p",
+			   __func__, hapd_iface);
 		os_free(hapd_iface);
 	}
 	return -1;
 }
 
 
+static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+{
+	size_t i;
+
+	wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
+
+	/* Remove hostapd_data only if it has already been initialized */
+	if (idx < iface->num_bss) {
+		struct hostapd_data *hapd = iface->bss[idx];
+
+		hostapd_bss_deinit(hapd);
+		wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+			   __func__, hapd, hapd->conf->iface);
+		hostapd_config_free_bss(hapd->conf);
+		os_free(hapd);
+
+		iface->num_bss--;
+
+		for (i = idx; i < iface->num_bss; i++)
+			iface->bss[i] = iface->bss[i + 1];
+	} else {
+		hostapd_config_free_bss(iface->conf->bss[idx]);
+		iface->conf->bss[idx] = NULL;
+	}
+
+	iface->conf->num_bss--;
+	for (i = idx; i < iface->conf->num_bss; i++)
+		iface->conf->bss[i] = iface->conf->bss[i + 1];
+
+	return 0;
+}
+
+
 int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
 {
 	struct hostapd_iface *hapd_iface;
-	size_t i, k = 0;
+	size_t i, j, k = 0;
 
 	for (i = 0; i < interfaces->count; i++) {
 		hapd_iface = interfaces->iface[i];
 		if (hapd_iface == NULL)
 			return -1;
-		if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+		if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
 			wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
 			hostapd_interface_deinit_free(hapd_iface);
 			k = i;
@@ -1405,12 +1949,15 @@
 			interfaces->count--;
 			return 0;
 		}
+
+		for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+			if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+				return hostapd_remove_bss(hapd_iface, j);
+		}
 	}
 	return -1;
 }
 
-#endif /* HOSTAPD */
-
 
 /**
  * hostapd_new_assoc_sta - Notify that a new station associated with the AP
@@ -1451,7 +1998,7 @@
 	 * IEEE 802.1X/WPA code will start accounting after the station has
 	 * been authorized. */
 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
-		os_get_time(&sta->connected_time);
+		os_get_reltime(&sta->connected_time);
 		accounting_sta_start(hapd, sta);
 	}
 
@@ -1464,11 +2011,274 @@
 	} else
 		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
 
-	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
-		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
-		   __func__, MAC2STR(sta->addr),
-		   hapd->conf->ap_max_inactivity);
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
-			       ap_handle_timer, hapd, sta);
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+		wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->conf->ap_max_inactivity);
+		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+				       ap_handle_timer, hapd, sta);
+	}
 }
+
+
+const char * hostapd_state_text(enum hostapd_iface_state s)
+{
+	switch (s) {
+	case HAPD_IFACE_UNINITIALIZED:
+		return "UNINITIALIZED";
+	case HAPD_IFACE_DISABLED:
+		return "DISABLED";
+	case HAPD_IFACE_COUNTRY_UPDATE:
+		return "COUNTRY_UPDATE";
+	case HAPD_IFACE_ACS:
+		return "ACS";
+	case HAPD_IFACE_HT_SCAN:
+		return "HT_SCAN";
+	case HAPD_IFACE_DFS:
+		return "DFS";
+	case HAPD_IFACE_ENABLED:
+		return "ENABLED";
+	}
+
+	return "UNKNOWN";
+}
+
+
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
+{
+	wpa_printf(MSG_INFO, "%s: interface state %s->%s",
+		   iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
+		   hostapd_state_text(s));
+	iface->state = s;
+}
+
+
+#ifdef NEED_AP_MLME
+
+static void free_beacon_data(struct beacon_data *beacon)
+{
+	os_free(beacon->head);
+	beacon->head = NULL;
+	os_free(beacon->tail);
+	beacon->tail = NULL;
+	os_free(beacon->probe_resp);
+	beacon->probe_resp = NULL;
+	os_free(beacon->beacon_ies);
+	beacon->beacon_ies = NULL;
+	os_free(beacon->proberesp_ies);
+	beacon->proberesp_ies = NULL;
+	os_free(beacon->assocresp_ies);
+	beacon->assocresp_ies = NULL;
+}
+
+
+static int hostapd_build_beacon_data(struct hostapd_iface *iface,
+				     struct beacon_data *beacon)
+{
+	struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
+	struct wpa_driver_ap_params params;
+	int ret;
+	struct hostapd_data *hapd = iface->bss[0];
+
+	os_memset(beacon, 0, sizeof(*beacon));
+	ret = ieee802_11_build_ap_params(hapd, &params);
+	if (ret < 0)
+		return ret;
+
+	ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
+					 &proberesp_extra,
+					 &assocresp_extra);
+	if (ret)
+		goto free_ap_params;
+
+	ret = -1;
+	beacon->head = os_malloc(params.head_len);
+	if (!beacon->head)
+		goto free_ap_extra_ies;
+
+	os_memcpy(beacon->head, params.head, params.head_len);
+	beacon->head_len = params.head_len;
+
+	beacon->tail = os_malloc(params.tail_len);
+	if (!beacon->tail)
+		goto free_beacon;
+
+	os_memcpy(beacon->tail, params.tail, params.tail_len);
+	beacon->tail_len = params.tail_len;
+
+	if (params.proberesp != NULL) {
+		beacon->probe_resp = os_malloc(params.proberesp_len);
+		if (!beacon->probe_resp)
+			goto free_beacon;
+
+		os_memcpy(beacon->probe_resp, params.proberesp,
+			  params.proberesp_len);
+		beacon->probe_resp_len = params.proberesp_len;
+	}
+
+	/* copy the extra ies */
+	if (beacon_extra) {
+		beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
+		if (!beacon->beacon_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->beacon_ies,
+			  beacon_extra->buf, wpabuf_len(beacon_extra));
+		beacon->beacon_ies_len = wpabuf_len(beacon_extra);
+	}
+
+	if (proberesp_extra) {
+		beacon->proberesp_ies =
+			os_malloc(wpabuf_len(proberesp_extra));
+		if (!beacon->proberesp_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
+			  wpabuf_len(proberesp_extra));
+		beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
+	}
+
+	if (assocresp_extra) {
+		beacon->assocresp_ies =
+			os_malloc(wpabuf_len(assocresp_extra));
+		if (!beacon->assocresp_ies)
+			goto free_beacon;
+
+		os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
+			  wpabuf_len(assocresp_extra));
+		beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
+	}
+
+	ret = 0;
+free_beacon:
+	/* if the function fails, the caller should not free beacon data */
+	if (ret)
+		free_beacon_data(beacon);
+
+free_ap_extra_ies:
+	hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
+				  assocresp_extra);
+free_ap_params:
+	ieee802_11_free_ap_params(&params);
+	return ret;
+}
+
+
+/*
+ * TODO: This flow currently supports only changing frequency within the
+ * same hw_mode. Any other changes to MAC parameters or provided settings (even
+ * width) are not supported.
+ */
+static int hostapd_change_config_freq(struct hostapd_data *hapd,
+				      struct hostapd_config *conf,
+				      struct hostapd_freq_params *params,
+				      struct hostapd_freq_params *old_params)
+{
+	int channel;
+
+	if (!params->channel) {
+		/* check if the new channel is supported by hw */
+		channel = hostapd_hw_get_channel(hapd, params->freq);
+		if (!channel)
+			return -1;
+	} else {
+		channel = params->channel;
+	}
+
+	/* if a pointer to old_params is provided we save previous state */
+	if (old_params) {
+		old_params->channel = conf->channel;
+		old_params->ht_enabled = conf->ieee80211n;
+		old_params->sec_channel_offset = conf->secondary_channel;
+	}
+
+	conf->channel = channel;
+	conf->ieee80211n = params->ht_enabled;
+	conf->secondary_channel = params->sec_channel_offset;
+
+	/* TODO: maybe call here hostapd_config_check here? */
+
+	return 0;
+}
+
+
+static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+				     struct csa_settings *settings)
+{
+	struct hostapd_freq_params old_freq;
+	int ret;
+
+	os_memset(&old_freq, 0, sizeof(old_freq));
+	if (!iface || !iface->freq || iface->csa_in_progress)
+		return -1;
+
+	ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+					 &settings->freq_params,
+					 &old_freq);
+	if (ret)
+		return ret;
+
+	ret = hostapd_build_beacon_data(iface, &settings->beacon_after);
+
+	/* change back the configuration */
+	hostapd_change_config_freq(iface->bss[0], iface->conf,
+				   &old_freq, NULL);
+
+	if (ret)
+		return ret;
+
+	/* set channel switch parameters for csa ie */
+	iface->cs_freq_params = settings->freq_params;
+	iface->cs_count = settings->cs_count;
+	iface->cs_block_tx = settings->block_tx;
+
+	ret = hostapd_build_beacon_data(iface, &settings->beacon_csa);
+	if (ret) {
+		free_beacon_data(&settings->beacon_after);
+		return ret;
+	}
+
+	settings->counter_offset_beacon = iface->cs_c_off_beacon;
+	settings->counter_offset_presp = iface->cs_c_off_proberesp;
+
+	return 0;
+}
+
+
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
+{
+	os_memset(&hapd->iface->cs_freq_params, 0,
+		  sizeof(hapd->iface->cs_freq_params));
+	hapd->iface->cs_count = 0;
+	hapd->iface->cs_block_tx = 0;
+	hapd->iface->cs_c_off_beacon = 0;
+	hapd->iface->cs_c_off_proberesp = 0;
+	hapd->iface->csa_in_progress = 0;
+}
+
+
+int hostapd_switch_channel(struct hostapd_data *hapd,
+			   struct csa_settings *settings)
+{
+	int ret;
+	ret = hostapd_fill_csa_settings(hapd->iface, settings);
+	if (ret)
+		return ret;
+
+	ret = hostapd_drv_switch_channel(hapd, settings);
+	free_beacon_data(&settings->beacon_csa);
+	free_beacon_data(&settings->beacon_after);
+
+	if (ret) {
+		/* if we failed, clean cs parameters */
+		hostapd_cleanup_cs_params(hapd);
+		return ret;
+	}
+
+	hapd->iface->csa_in_progress = 1;
+	return 0;
+}
+
+#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52..489ab16 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,14 +11,13 @@
 
 #include "common/defs.h"
 #include "ap_config.h"
+#include "drivers/driver.h"
 
-struct wpa_driver_ops;
 struct wpa_ctrl_dst;
 struct radius_server_data;
 struct upnp_wps_device_sm;
 struct hostapd_data;
 struct sta_info;
-struct hostap_sta_driver_data;
 struct ieee80211_ht_capabilities;
 struct full_dynamic_vlan;
 enum wps_event;
@@ -42,9 +41,13 @@
 	int global_ctrl_sock;
 	char *global_iface_path;
 	char *global_iface_name;
+#ifndef CONFIG_NATIVE_WINDOWS
 	gid_t ctrl_iface_group;
+#endif /* CONFIG_NATIVE_WINDOWS */
 	struct hostapd_iface **iface;
 	struct hostapd_dynamic_iface **dynamic_iface;
+
+	size_t terminate_on_error;
 };
 
 enum hostapd_chan_status {
@@ -100,6 +103,7 @@
 	struct hostapd_config *iconf;
 	struct hostapd_bss_config *conf;
 	int interface_added; /* virtual interface added for this BSS */
+	unsigned int started:1;
 
 	u8 own_addr[ETH_ALEN];
 
@@ -139,7 +143,7 @@
 	struct eapol_authenticator *eapol_auth;
 
 	struct rsn_preauth_interface *preauth_iface;
-	time_t michael_mic_failure;
+	struct os_reltime michael_mic_failure;
 	int michael_mic_failures;
 	int tkip_countermeasures;
 
@@ -234,8 +238,12 @@
 #ifdef CONFIG_SAE
 	/** Key used for generating SAE anti-clogging tokens */
 	u8 sae_token_key[8];
-	os_time_t last_sae_token_key_update;
+	struct os_reltime last_sae_token_key_update;
 #endif /* CONFIG_SAE */
+
+#ifdef CONFIG_TESTING_OPTIONS
+	int ext_mgmt_frame_handling;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -247,10 +255,24 @@
 	void *owner;
 	char *config_fname;
 	struct hostapd_config *conf;
+	char phy[16]; /* Name of the PHY (radio) */
+
+	enum hostapd_iface_state {
+		HAPD_IFACE_UNINITIALIZED,
+		HAPD_IFACE_DISABLED,
+		HAPD_IFACE_COUNTRY_UPDATE,
+		HAPD_IFACE_ACS,
+		HAPD_IFACE_HT_SCAN,
+		HAPD_IFACE_DFS,
+		HAPD_IFACE_ENABLED
+	} state;
 
 	size_t num_bss;
 	struct hostapd_data **bss;
 
+	unsigned int wait_channel_update:1;
+	unsigned int cac_started:1;
+
 	int num_ap; /* number of entries in ap_list */
 	struct ap_info *ap_list; /* AP info list head */
 	struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -315,6 +337,14 @@
 	/* lowest observed noise floor in dBm */
 	s8 lowest_nf;
 
+	/* channel switch parameters */
+	struct hostapd_freq_params cs_freq_params;
+	u8 cs_count;
+	int cs_block_tx;
+	unsigned int cs_c_off_beacon;
+	unsigned int cs_c_off_proberesp;
+	int csa_in_progress;
+
 #ifdef CONFIG_ACS
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
@@ -345,6 +375,11 @@
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
 void hostapd_interface_deinit(struct hostapd_iface *iface);
 void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+				    const char *config_file);
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+			   const char *config_fname, int debug);
 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   int reassoc);
 void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -353,6 +388,12 @@
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
+const char * hostapd_state_text(enum hostapd_iface_state s);
+int hostapd_switch_channel(struct hostapd_data *hapd,
+			   struct csa_settings *settings);
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
 
 /* utils.c */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@@ -374,7 +415,7 @@
 			 const u8 *bssid, const u8 *ie, size_t ie_len,
 			 int ssi_signal);
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset);
+			     int offset, int width, int cf1, int cf2);
 
 const struct hostapd_eap_user *
 hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8a239f4..4e66379 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -4,14 +4,8 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -20,7 +14,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
+#include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
@@ -45,6 +39,36 @@
 }
 
 
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static char * dfs_info(struct hostapd_channel_data *chan)
+{
+	static char info[256];
+	char *state;
+
+	switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
+	case HOSTAPD_CHAN_DFS_UNKNOWN:
+		state = "unknown";
+		break;
+	case HOSTAPD_CHAN_DFS_USABLE:
+		state = "usable";
+		break;
+	case HOSTAPD_CHAN_DFS_UNAVAILABLE:
+		state = "unavailable";
+		break;
+	case HOSTAPD_CHAN_DFS_AVAILABLE:
+		state = "available";
+		break;
+	default:
+		return "";
+	}
+	os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
+	info[sizeof(info) - 1] = '\0';
+
+	return info;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
 int hostapd_get_hw_features(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
@@ -71,30 +95,40 @@
 
 	for (i = 0; i < num_modes; i++) {
 		struct hostapd_hw_modes *feature = &modes[i];
+		int dfs_enabled = hapd->iconf->ieee80211h &&
+			(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+
 		/* set flag for channels we can use in current regulatory
 		 * domain */
 		for (j = 0; j < feature->num_channels; j++) {
+			int dfs = 0;
+
 			/*
 			 * Disable all channels that are marked not to allow
-			 * IBSS operation or active scanning. In addition,
-			 * disable all channels that require radar detection,
-			 * since that (in addition to full DFS) is not yet
-			 * supported.
+			 * IBSS operation or active scanning.
+			 * Use radar channels only if the driver supports DFS.
 			 */
-			if (feature->channels[j].flag &
-			    (HOSTAPD_CHAN_NO_IBSS |
-			     HOSTAPD_CHAN_PASSIVE_SCAN |
-			     HOSTAPD_CHAN_RADAR))
+			if ((feature->channels[j].flag &
+			     HOSTAPD_CHAN_RADAR) && dfs_enabled) {
+				dfs = 1;
+			} else if (feature->channels[j].flag &
+				   (HOSTAPD_CHAN_NO_IBSS |
+				    HOSTAPD_CHAN_PASSIVE_SCAN |
+				    HOSTAPD_CHAN_RADAR)) {
 				feature->channels[j].flag |=
 					HOSTAPD_CHAN_DISABLED;
+			}
+
 			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
+
 			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
-				   "chan=%d freq=%d MHz max_tx_power=%d dBm",
+				   "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
 				   feature->mode,
 				   feature->channels[j].chan,
 				   feature->channels[j].freq,
-				   feature->channels[j].max_tx_power);
+				   feature->channels[j].max_tx_power,
+				   dfs ? dfs_info(&feature->channels[j]) : "");
 		}
 	}
 
@@ -230,7 +264,7 @@
 		first = sec_chan;
 
 	ok = 0;
-	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
 		if (first == allowed[k]) {
 			ok = 1;
 			break;
@@ -491,6 +525,47 @@
 }
 
 
+static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
+					struct wpa_driver_scan_params *params)
+{
+	/* Scan only the affected frequency range */
+	int pri_freq;
+	int affected_start, affected_end;
+	int i, pos;
+	struct hostapd_hw_modes *mode;
+
+	if (iface->current_mode == NULL)
+		return;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0) {
+		affected_start = pri_freq - 10;
+		affected_end = pri_freq + 30;
+	} else {
+		affected_start = pri_freq - 30;
+		affected_end = pri_freq + 10;
+	}
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+
+	mode = iface->current_mode;
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	pos = 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (chan->freq < affected_start ||
+		    chan->freq > affected_end)
+			continue;
+		params->freqs[pos++] = chan->freq;
+	}
+}
+
+
 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
 {
 	struct wpa_driver_scan_params params;
@@ -498,11 +573,14 @@
 	if (!iface->conf->secondary_channel)
 		return 0; /* HT40 not used */
 
+	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
 	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
 		   "40 MHz channel");
 	os_memset(&params, 0, sizeof(params));
 	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
 		ieee80211n_scan_channels_2g4(iface, &params);
+	else
+		ieee80211n_scan_channels_5g(iface, &params);
 	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
 		wpa_printf(MSG_ERROR, "Failed to request a scan of "
 			   "neighboring BSSes");
@@ -613,6 +691,92 @@
 	return 1;
 }
 
+
+#ifdef CONFIG_IEEE80211AC
+
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+	u32 req_cap = conf & cap;
+
+	/*
+	 * Make sure we support all requested capabilities.
+	 * NOTE: We assume that 'cap' represents a capability mask,
+	 * not a discrete value.
+	 */
+	if ((hw & req_cap) != req_cap) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
+			   name);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+				     const char *name)
+{
+	u32 hw_max = hw & cap;
+	u32 conf_val = conf & cap;
+
+	if (conf_val > hw_max) {
+		int offset = find_first_bit(cap);
+		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+			   name, conf_val >> offset, hw_max >> offset);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
+{
+	u32 hw = iface->current_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);
+
+#define VHT_CAP_CHECK(cap) \
+	do { \
+		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+	do { \
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+	return 1;
+}
+#endif /* CONFIG_IEEE80211AC */
+
 #endif /* CONFIG_IEEE80211N */
 
 
@@ -624,6 +788,10 @@
 		return 0;
 	if (!ieee80211n_supported_ht_capab(iface))
 		return -1;
+#ifdef CONFIG_IEEE80211AC
+	if (!ieee80211ac_supported_vht_capab(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211AC */
 	ret = ieee80211n_check_40mhz(iface);
 	if (ret)
 		return ret;
@@ -718,33 +886,45 @@
 }
 
 
-int hostapd_acs_completed(struct hostapd_iface *iface)
+int hostapd_acs_completed(struct hostapd_iface *iface, int err)
 {
-	int ret;
+	int ret = -1;
+
+	if (err)
+		goto out;
 
 	switch (hostapd_check_chans(iface)) {
 	case HOSTAPD_CHAN_VALID:
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
+			ACS_EVENT_COMPLETED "freq=%d channel=%d",
+			hostapd_hw_get_freq(iface->bss[0],
+					    iface->conf->channel),
+			iface->conf->channel);
 		break;
 	case HOSTAPD_CHAN_ACS:
 		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
-		return -1;
+		goto out;
 	case HOSTAPD_CHAN_INVALID:
 	default:
 		wpa_printf(MSG_ERROR, "ACS picked unusable channels");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
-		return -1;
+		goto out;
 	}
 
 	ret = hostapd_check_ht_capab(iface);
 	if (ret < 0)
-		return -1;
+		goto out;
 	if (ret == 1) {
 		wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
 		return 0;
 	}
 
-	return hostapd_setup_interface_complete(iface, 0);
+	ret = 0;
+out:
+	return hostapd_setup_interface_complete(iface, ret);
 }
 
 
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index abadcd1..783ae5e 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -4,14 +4,8 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef HW_FEATURES_H
@@ -21,6 +15,7 @@
 void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
 			      size_t num_hw_features);
 int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_acs_completed(struct hostapd_iface *iface, int err);
 int hostapd_select_hw_mode(struct hostapd_iface *iface);
 const char * hostapd_hw_mode_txt(int mode);
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index be55c69..bad080f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -204,7 +204,7 @@
 	addr.sin_port = htons(IAPP_UDP_PORT);
 	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
 		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
-		perror("sendto[IAPP-ADD]");
+		wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
 }
 
 
@@ -231,7 +231,7 @@
 				   * FIX: what is correct RW with 802.11? */
 
 	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
-		perror("send[L2 Update]");
+		wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
 }
 
 
@@ -276,8 +276,8 @@
 	struct sta_info *sta;
 
 	if (len != sizeof(*add)) {
-		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
-		       len, (unsigned long) sizeof(*add));
+		wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
+			   len, (unsigned long) sizeof(*add));
 		return;
 	}
 
@@ -326,7 +326,8 @@
 	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (len < 0) {
-		perror("recvfrom");
+		wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -350,17 +351,18 @@
 		       hdr->version, hdr->command,
 		       be_to_host16(hdr->identifier), hlen);
 	if (hdr->version != IAPP_VERSION) {
-		printf("Dropping IAPP frame with unknown version %d\n",
-		       hdr->version);
+		wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
+			   hdr->version);
 		return;
 	}
 	if (hlen > len) {
-		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+		wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
+			   hlen, len);
 		return;
 	}
 	if (hlen < len) {
-		printf("Ignoring %d extra bytes from IAPP frame\n",
-		       len - hlen);
+		wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
+			   len - hlen);
 		len = hlen;
 	}
 
@@ -376,7 +378,7 @@
 		/* TODO: process */
 		break;
 	default:
-		printf("Unknown IAPP command %d\n", hdr->command);
+		wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
 		break;
 	}
 }
@@ -403,7 +405,8 @@
 
 	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (iapp->udp_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -411,35 +414,38 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
 	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	ifindex = ifr.ifr_ifindex;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	iapp->own.s_addr = paddr->sin_addr.s_addr;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFBRDADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -450,7 +456,8 @@
 	uaddr.sin_port = htons(IAPP_UDP_PORT);
 	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
 		 sizeof(uaddr)) < 0) {
-		perror("bind[UDP]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -461,14 +468,16 @@
 	mreq.imr_ifindex = 0;
 	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
 		       sizeof(mreq)) < 0) {
-		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (iapp->packet_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -478,19 +487,20 @@
 	addr.sll_ifindex = ifindex;
 	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
 		 sizeof(addr)) < 0) {
-		perror("bind[PACKET]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
 				     iapp, NULL)) {
-		printf("Could not register read socket for IAPP.\n");
+		wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
-	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+	wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
 
 	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
 	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@@ -515,7 +525,8 @@
 		mreq.imr_ifindex = 0;
 		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
 			       &mreq, sizeof(mreq)) < 0) {
-			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+			wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
+				   strerror(errno));
 		}
 
 		eloop_unregister_read_sock(iapp->udp_sock);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 781f826..9251ac3 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -15,7 +15,6 @@
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
 #include "crypto/random.h"
-#include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
@@ -179,21 +178,6 @@
 }
 
 
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
-{
-	int i;
-	if (len > HOSTAPD_MAX_SSID_LEN)
-		len = HOSTAPD_MAX_SSID_LEN;
-	for (i = 0; i < len; i++) {
-		if (ssid[i] >= 32 && ssid[i] < 127)
-			buf[i] = ssid[i];
-		else
-			buf[i] = '.';
-	}
-	buf[len] = '\0';
-}
-
-
 static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 			   u16 auth_transaction, const u8 *challenge,
 			   int iswep)
@@ -239,13 +223,8 @@
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG,
 		       "authentication OK (shared key)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
-	/* Station will be marked authenticated if it ACKs the
-	 * authentication reply. */
-#else
 	sta->flags |= WLAN_STA_AUTH;
 	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-#endif
 	os_free(sta->challenge);
 	sta->challenge = NULL;
 
@@ -286,7 +265,7 @@
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
 	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
-		perror("send_auth_reply: send");
+		wpa_printf(MSG_INFO, "send_auth_reply: send");
 
 	os_free(buf);
 }
@@ -411,17 +390,17 @@
 {
 	struct wpabuf *buf;
 	u8 *token;
-	struct os_time t;
+	struct os_reltime now;
 
-	os_get_time(&t);
-	if (hapd->last_sae_token_key_update == 0 ||
-	    t.sec > hapd->last_sae_token_key_update + 60) {
+	os_get_reltime(&now);
+	if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
+	    os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
 		if (random_get_bytes(hapd->sae_token_key,
 				     sizeof(hapd->sae_token_key)) < 0)
 			return NULL;
 		wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
 			    hapd->sae_token_key, sizeof(hapd->sae_token_key));
-		hapd->last_sae_token_key_update = t.sec;
+		hapd->last_sae_token_key_update = now;
 	}
 
 	buf = wpabuf_alloc(SHA256_MAC_LEN);
@@ -492,6 +471,7 @@
 				       HOSTAPD_LEVEL_DEBUG,
 				       "SAE confirm before commit");
 			resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+			goto failed;
 		}
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -523,6 +503,7 @@
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 	}
 
+failed:
 	sta->auth_alg = WLAN_AUTH_SAE;
 
 	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
@@ -552,8 +533,8 @@
 	char *radius_cui = NULL;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -601,23 +582,23 @@
 #endif /* CONFIG_SAE */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
 	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
-		printf("Unsupported authentication algorithm (%d)\n",
-		       auth_alg);
+		wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
+			   auth_alg);
 		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
 		goto fail;
 	}
 
 	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
 	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
-		printf("Unknown authentication transaction number (%d)\n",
-		       auth_transaction);
+		wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
+			   auth_transaction);
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 		goto fail;
 	}
 
 	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -628,8 +609,8 @@
 				      &psk, &identity, &radius_cui);
 
 	if (res == HOSTAPD_ACL_REJECT) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -691,15 +672,10 @@
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "authentication OK (open system)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
-		/* Station will be marked authenticated if it ACKs the
-		 * authentication reply. */
-#else
 		sta->flags |= WLAN_STA_AUTH;
 		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
 		sta->auth_alg = WLAN_AUTH_OPEN;
 		mlme_authenticate_indication(hapd, sta);
-#endif
 		break;
 	case WLAN_AUTH_SHARED_KEY:
 		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -792,12 +768,10 @@
 
 	if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
 	    os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
-		char ssid_txt[33];
-		ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO,
 			       "Station tried to associate with unknown SSID "
-			       "'%s'", ssid_txt);
+			       "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
@@ -859,6 +833,21 @@
 }
 
 
+static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+			   const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+	/* check for QoS Map support */
+	if (ext_capab_ie_len >= 5) {
+		if (ext_capab_ie[4] & 0x01)
+			sta->qos_map_enabled = 1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *ies, size_t ies_len, int reassoc)
 {
@@ -881,6 +870,9 @@
 	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
+	resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
 	resp = copy_supp_rates(hapd, sta, &elems);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
@@ -903,12 +895,17 @@
 				  elems.vht_capabilities_len);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
+
+	resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+
 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
 	    !(sta->flags & WLAN_STA_VHT)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "Station does not support "
 			       "mandatory VHT PHY - reject association");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
 	}
 #endif /* CONFIG_IEEE80211AC */
 
@@ -1050,7 +1047,9 @@
 
 #ifdef CONFIG_SAE
 		if (wpa_auth_uses_sae(sta->wpa_sm) &&
-		    sta->auth_alg != WLAN_AUTH_SAE) {
+		    sta->auth_alg != WLAN_AUTH_SAE &&
+		    !(sta->auth_alg == WLAN_AUTH_FT &&
+		      wpa_auth_uses_ft_sae(sta->wpa_sm))) {
 			wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
 				   "SAE AKM after non-SAE auth_alg %u",
 				   MAC2STR(sta->addr), sta->auth_alg);
@@ -1135,8 +1134,7 @@
 	reply->u.assoc_resp.capab_info =
 		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
 	reply->u.assoc_resp.status_code = host_to_le16(status_code);
-	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
-					       | BIT(14) | BIT(15));
+	reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
 	/* Supported rates */
 	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
 	/* Extended supported rates */
@@ -1169,6 +1167,8 @@
 
 	p = hostapd_eid_ext_capab(hapd, p);
 	p = hostapd_eid_bss_max_idle_period(hapd, p);
+	if (sta->qos_map_enabled)
+		p = hostapd_eid_qos_map_set(hapd, p);
 
 	if (sta->flags & WLAN_STA_WMM)
 		p = hostapd_eid_wmm(hapd, p);
@@ -1235,8 +1235,8 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
 				      sizeof(mgmt->u.assoc_req))) {
-		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
-		       "\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
@@ -1422,8 +1422,8 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
-		printf("handle_disassoc - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1433,8 +1433,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		printf("Station " MACSTR " trying to disassociate, but it "
-		       "is not associated.\n", MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
+			   MAC2STR(mgmt->sa));
 		return;
 	}
 
@@ -1508,8 +1508,8 @@
 	struct ieee802_11_elems elems;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
-		printf("handle_beacon - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1524,9 +1524,9 @@
 
 #ifdef CONFIG_IEEE80211W
 
-static void hostapd_sa_query_action(struct hostapd_data *hapd,
-				    const struct ieee80211_mgmt *mgmt,
-				    size_t len)
+static int hostapd_sa_query_action(struct hostapd_data *hapd,
+				   const struct ieee80211_mgmt *mgmt,
+				   size_t len)
 {
 	const u8 *end;
 
@@ -1535,12 +1535,13 @@
 	if (((u8 *) mgmt) + len < end) {
 		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
 			   "frame (len=%lu)", (unsigned long) len);
-		return;
+		return 0;
 	}
 
 	ieee802_11_sa_query_action(hapd, mgmt->sa,
 				   mgmt->u.action.u.sa_query_resp.action,
 				   mgmt->u.action.u.sa_query_resp.trans_id);
+	return 1;
 }
 
 
@@ -1552,29 +1553,8 @@
 #endif /* CONFIG_IEEE80211W */
 
 
-#ifdef CONFIG_WNM
-static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
-			       const struct ieee80211_mgmt *mgmt,
-			       size_t len)
-{
-	struct rx_action action;
-	if (len < IEEE80211_HDRLEN + 2)
-		return;
-	os_memset(&action, 0, sizeof(action));
-	action.da = mgmt->da;
-	action.sa = mgmt->sa;
-	action.bssid = mgmt->bssid;
-	action.category = mgmt->u.action.category;
-	action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
-	action.len = len - IEEE80211_HDRLEN - 1;
-	action.freq = hapd->iface->freq;
-	ieee802_11_rx_wnm_action_ap(hapd, &action);
-}
-#endif /* CONFIG_WNM */
-
-
-static void handle_action(struct hostapd_data *hapd,
-			  const struct ieee80211_mgmt *mgmt, size_t len)
+static int handle_action(struct hostapd_data *hapd,
+			 const struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct sta_info *sta;
 	sta = ap_get_sta(hapd, mgmt->sa);
@@ -1584,7 +1564,7 @@
 			       HOSTAPD_LEVEL_DEBUG,
 			       "handle_action - too short payload (len=%lu)",
 			       (unsigned long) len);
-		return;
+		return 0;
 	}
 
 	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
@@ -1592,18 +1572,18 @@
 		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
 			   "frame (category=%u) from unassociated STA " MACSTR,
 			   MAC2STR(mgmt->sa), mgmt->u.action.category);
-		return;
+		return 0;
 	}
 
 #ifdef CONFIG_IEEE80211W
 	if (sta && (sta->flags & WLAN_STA_MFP) &&
-	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
-	      robust_action_frame(mgmt->u.action.category))) {
+	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
+	    robust_action_frame(mgmt->u.action.category)) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "Dropped unprotected Robust Action frame from "
 			       "an MFP STA");
-		return;
+		return 0;
 	}
 #endif /* CONFIG_IEEE80211W */
 
@@ -1613,22 +1593,22 @@
 		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
 				     len - IEEE80211_HDRLEN))
 			break;
-		return;
+		return 1;
 #endif /* CONFIG_IEEE80211R */
 	case WLAN_ACTION_WMM:
 		hostapd_wmm_action(hapd, mgmt, len);
-		return;
+		return 1;
 #ifdef CONFIG_IEEE80211W
 	case WLAN_ACTION_SA_QUERY:
-		hostapd_sa_query_action(hapd, mgmt, len);
-		return;
+		return hostapd_sa_query_action(hapd, mgmt, len);
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM
 	case WLAN_ACTION_WNM:
-		hostapd_wnm_action(hapd, sta, mgmt, len);
-		return;
+		ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
+		return 1;
 #endif /* CONFIG_WNM */
 	case WLAN_ACTION_PUBLIC:
+	case WLAN_ACTION_PROTECTED_DUAL:
 		if (hapd->public_action_cb) {
 			hapd->public_action_cb(hapd->public_action_cb_ctx,
 					       (u8 *) mgmt, len,
@@ -1640,14 +1620,14 @@
 						hapd->iface->freq);
 		}
 		if (hapd->public_action_cb || hapd->public_action_cb2)
-			return;
+			return 1;
 		break;
 	case WLAN_ACTION_VENDOR_SPECIFIC:
 		if (hapd->vendor_action_cb) {
 			if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
 						   (u8 *) mgmt, len,
 						   hapd->iface->freq) == 0)
-				return;
+				return 1;
 		}
 		break;
 	}
@@ -1670,7 +1650,7 @@
 			   "frame back to sender");
 		resp = os_malloc(len);
 		if (resp == NULL)
-			return;
+			return 0;
 		os_memcpy(resp, mgmt, len);
 		os_memcpy(resp->da, resp->sa, ETH_ALEN);
 		os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
@@ -1683,6 +1663,8 @@
 		}
 		os_free(resp);
 	}
+
+	return 1;
 }
 
 
@@ -1699,15 +1681,29 @@
  * addition, it can be called to re-inserted pending frames (e.g., when using
  * external RADIUS server as an MAC ACL).
  */
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
-		     struct hostapd_frame_info *fi)
+int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		    struct hostapd_frame_info *fi)
 {
 	struct ieee80211_mgmt *mgmt;
 	int broadcast;
 	u16 fc, stype;
+	int ret = 0;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->ext_mgmt_frame_handling) {
+		size_t hex_len = 2 * len + 1;
+		char *hex = os_malloc(hex_len);
+		if (hex) {
+			wpa_snprintf_hex(hex, hex_len, buf, len);
+			wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
+			os_free(hex);
+		}
+		return 1;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	if (len < 24)
-		return;
+		return 0;
 
 	mgmt = (struct ieee80211_mgmt *) buf;
 	fc = le_to_host16(mgmt->frame_control);
@@ -1715,7 +1711,7 @@
 
 	if (stype == WLAN_FC_STYPE_BEACON) {
 		handle_beacon(hapd, mgmt, len, fi);
-		return;
+		return 1;
 	}
 
 	broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
@@ -1729,15 +1725,15 @@
 	      stype == WLAN_FC_STYPE_ACTION) &&
 #endif /* CONFIG_P2P */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
-		printf("MGMT: BSSID=" MACSTR " not our address\n",
-		       MAC2STR(mgmt->bssid));
-		return;
+		wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
+			   MAC2STR(mgmt->bssid));
+		return 0;
 	}
 
 
 	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
 		handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
-		return;
+		return 1;
 	}
 
 	if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
@@ -1745,33 +1741,38 @@
 			       HOSTAPD_LEVEL_DEBUG,
 			       "MGMT: DA=" MACSTR " not our address",
 			       MAC2STR(mgmt->da));
-		return;
+		return 0;
 	}
 
 	switch (stype) {
 	case WLAN_FC_STYPE_AUTH:
 		wpa_printf(MSG_DEBUG, "mgmt::auth");
 		handle_auth(hapd, mgmt, len);
+		ret = 1;
 		break;
 	case WLAN_FC_STYPE_ASSOC_REQ:
 		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
 		handle_assoc(hapd, mgmt, len, 0);
+		ret = 1;
 		break;
 	case WLAN_FC_STYPE_REASSOC_REQ:
 		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
 		handle_assoc(hapd, mgmt, len, 1);
+		ret = 1;
 		break;
 	case WLAN_FC_STYPE_DISASSOC:
 		wpa_printf(MSG_DEBUG, "mgmt::disassoc");
 		handle_disassoc(hapd, mgmt, len);
+		ret = 1;
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
 		handle_deauth(hapd, mgmt, len);
+		ret = 1;
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action");
-		handle_action(hapd, mgmt, len);
+		ret = handle_action(hapd, mgmt, len);
 		break;
 	default:
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1779,6 +1780,8 @@
 			       "unknown mgmt frame subtype %d", stype);
 		break;
 	}
+
+	return ret;
 }
 
 
@@ -1797,8 +1800,8 @@
 	}
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth_cb - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1808,8 +1811,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_auth_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -1859,15 +1862,15 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
 				      sizeof(mgmt->u.assoc_resp))) {
-		printf("handle_assoc_cb(reassoc=%d) - too short payload "
-		       "(len=%lu)\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_assoc_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -1899,6 +1902,7 @@
 	if (sta->flags & WLAN_STA_ASSOC)
 		new_assoc = 0;
 	sta->flags |= WLAN_STA_ASSOC;
+	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
 	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
 	    sta->auth_alg == WLAN_AUTH_FT) {
 		/*
@@ -1938,7 +1942,7 @@
 			    sta->listen_interval,
 			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
 			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
-			    sta->flags, sta->qosinfo)) {
+			    sta->flags, sta->qosinfo, sta->vht_opmode)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_NOTICE,
 			       "Could not add STA to kernel driver");
@@ -2055,6 +2059,14 @@
 	const struct ieee80211_mgmt *mgmt;
 	mgmt = (const struct ieee80211_mgmt *) buf;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->ext_mgmt_frame_handling) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d",
+			stype, ok);
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	switch (stype) {
 	case WLAN_FC_STYPE_AUTH:
 		wpa_printf(MSG_DEBUG, "mgmt::auth cb");
@@ -2083,7 +2095,7 @@
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
 		break;
 	default:
-		printf("unknown mgmt cb frame subtype %d\n", stype);
+		wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
 		break;
 	}
 }
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 2aab56d..809b4ca 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -15,11 +15,10 @@
 struct hostapd_frame_info;
 struct ieee80211_ht_capabilities;
 
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
-		     struct hostapd_frame_info *fi);
+int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		    struct hostapd_frame_info *fi);
 void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
 			u16 stype, int ok);
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
 #ifdef NEED_AP_MLME
 int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
 int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@@ -41,6 +40,7 @@
 u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
 			   int probe);
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
@@ -61,6 +61,8 @@
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_capab, size_t vht_capab_len);
+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,
 		       const u8 *buf, size_t len, int ack);
 void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index c311e55..56c3ce0 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -29,7 +29,7 @@
 
 
 struct hostapd_cached_radius_acl {
-	os_time_t timestamp;
+	struct os_reltime timestamp;
 	macaddr addr;
 	int accepted; /* HOSTAPD_ACL_* */
 	struct hostapd_cached_radius_acl *next;
@@ -43,7 +43,7 @@
 
 
 struct hostapd_acl_query_data {
-	os_time_t timestamp;
+	struct os_reltime timestamp;
 	u8 radius_id;
 	macaddr addr;
 	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@@ -104,15 +104,16 @@
 				 char **identity, char **radius_cui)
 {
 	struct hostapd_cached_radius_acl *entry;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	for (entry = hapd->acl_cache; entry; entry = entry->next) {
 		if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
 			continue;
 
-		if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+		if (os_reltime_expired(&now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT))
 			return -1; /* entry has expired */
 		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			if (session_timeout)
@@ -265,7 +266,6 @@
 		return HOSTAPD_ACL_REJECT;
 #else /* CONFIG_NO_RADIUS */
 		struct hostapd_acl_query_data *query;
-		struct os_time t;
 
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
@@ -305,8 +305,7 @@
 			wpa_printf(MSG_ERROR, "malloc for query data failed");
 			return HOSTAPD_ACL_REJECT;
 		}
-		os_get_time(&t);
-		query->timestamp = t.sec;
+		os_get_reltime(&query->timestamp);
 		os_memcpy(query->addr, addr, ETH_ALEN);
 		if (hostapd_radius_acl_query(hapd, addr, query)) {
 			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -338,7 +337,8 @@
 
 
 #ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
+				     struct os_reltime *now)
 {
 	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
 
@@ -346,7 +346,8 @@
 	entry = hapd->acl_cache;
 
 	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+		if (os_reltime_expired(now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT)) {
 			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
 				   " has expired.", MAC2STR(entry->addr));
 			if (prev)
@@ -367,7 +368,7 @@
 
 
 static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
-				       os_time_t now)
+				       struct os_reltime *now)
 {
 	struct hostapd_acl_query_data *prev, *entry, *tmp;
 
@@ -375,7 +376,8 @@
 	entry = hapd->acl_queries;
 
 	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+		if (os_reltime_expired(now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT)) {
 			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
 				   " has expired.", MAC2STR(entry->addr));
 			if (prev)
@@ -403,11 +405,11 @@
 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 {
 	struct hostapd_data *hapd = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
-	hostapd_acl_expire_cache(hapd, now.sec);
-	hostapd_acl_expire_queries(hapd, now.sec);
+	os_get_reltime(&now);
+	hostapd_acl_expire_cache(hapd, &now);
+	hostapd_acl_expire_queries(hapd, &now);
 
 	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
 }
@@ -480,7 +482,6 @@
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-	struct os_time t;
 
 	query = hapd->acl_queries;
 	prev = NULL;
@@ -515,8 +516,7 @@
 		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
 		goto done;
 	}
-	os_get_time(&t);
-	cache->timestamp = t.sec;
+	os_get_reltime(&cache->timestamp);
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
 		u8 *buf;
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6483e1c..31dc47e 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -3,21 +3,14 @@
  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007-2008, Intel Corporation
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "sta_info.h"
@@ -50,6 +43,22 @@
 
  	pos += sizeof(*cap);
 
+	if (hapd->iconf->obss_interval) {
+		struct ieee80211_obss_scan_parameters *scan_params;
+
+		*pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS;
+		*pos++ = sizeof(*scan_params);
+
+		scan_params = (struct ieee80211_obss_scan_parameters *) pos;
+		os_memset(scan_params, 0, sizeof(*scan_params));
+		scan_params->width_trigger_scan_interval =
+			host_to_le16(hapd->iconf->obss_interval);
+
+		/* TODO: Fill in more parameters (supplicant ignores them) */
+
+		pos += sizeof(*scan_params);
+	}
+
 	return pos;
 }
 
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index c36bbe3..eadaa4d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -24,13 +24,13 @@
 {
 	u8 *pos = eid;
 	u32 timeout, tu;
-	struct os_time now, passed;
+	struct os_reltime now, passed;
 
 	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
 	*pos++ = 5;
 	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &sta->sa_query_start, &passed);
 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
 	if (hapd->conf->assoc_sa_query_max_timeout > tu)
 		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
@@ -69,7 +69,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
+		wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
 }
 
 
@@ -107,7 +107,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
-		perror("ieee80211_mgmt_sa_query_request: send");
+		wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
 }
 
 
@@ -189,6 +189,8 @@
 			*pos |= 0x80; /* Bit 31 - Interworking */
 		break;
 	case 4: /* Bits 32-39 */
+		if (hapd->conf->qos_map_set_len)
+			*pos |= 0x01; /* Bit 32 - QoS Map */
 		if (hapd->conf->tdls & TDLS_PROHIBIT)
 			*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
 		if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
@@ -250,6 +252,23 @@
 }
 
 
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = hapd->conf->qos_map_set_len;
+
+	if (!len)
+		return eid;
+
+	*pos++ = WLAN_EID_QOS_MAP_SET;
+	*pos++ = len;
+	os_memcpy(pos, hapd->conf->qos_map_set, len);
+	pos += len;
+
+	return pos;
+}
+
+
 u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 *pos = eid;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0012c0f..221d9c2 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -12,7 +12,6 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "sta_info.h"
@@ -35,7 +34,7 @@
 	cap = (struct ieee80211_vht_capabilities *) pos;
 	os_memset(cap, 0, sizeof(*cap));
 	cap->vht_capabilities_info = host_to_le32(
-		hapd->iface->current_mode->vht_capab);
+		hapd->iface->conf->vht_capab);
 
 	/* Supported MCS set comes from hw */
 	os_memcpy(&cap->vht_supported_mcs_set,
@@ -109,13 +108,93 @@
 	return WLAN_STATUS_SUCCESS;
 }
 
+
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *vht_oper_notif)
+{
+	u8 channel_width;
+
+	if (!vht_oper_notif) {
+		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
+
+	if (channel_width != VHT_CHANWIDTH_USE_HT &&
+	    channel_width != VHT_CHANWIDTH_80MHZ &&
+	    channel_width != VHT_CHANWIDTH_160MHZ &&
+	    channel_width != VHT_CHANWIDTH_80P80MHZ &&
+	    ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >>
+	     VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) {
+		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
+	sta->vht_opmode = *vht_oper_notif;
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 void hostapd_get_vht_capab(struct hostapd_data *hapd,
 			   struct ieee80211_vht_capabilities *vht_cap,
 			   struct ieee80211_vht_capabilities *neg_vht_cap)
 {
+	u32 cap, own_cap, sym_caps;
+
 	if (vht_cap == NULL)
 		return;
 	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
 
-	/* TODO: mask own capabilities, like get_ht_capab() */
+	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
+	own_cap = hapd->iconf->vht_capab;
+
+	/* mask out symmetric VHT capabilities we don't support */
+	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
+	cap &= ~sym_caps | (own_cap & sym_caps);
+
+	/* mask out beamformer/beamformee caps if not supported */
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+			 VHT_CAP_BEAMFORMEE_STS_MAX);
+
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
+			 VHT_CAP_SOUNDING_DIMENSION_MAX);
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+	/* mask channel widths we don't support */
+	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+		break;
+	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
+			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+		}
+		break;
+	default:
+		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+		break;
+	}
+
+	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+		cap &= ~VHT_CAP_SHORT_GI_160;
+
+	/*
+	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+	 */
+	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
+		cap &= ~VHT_CAP_TXSTBC;
+	if (!(own_cap & VHT_CAP_TXSTBC))
+		cap &= ~VHT_CAP_RXSTBC_MASK;
+
+	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
 }
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 9867581..21f815a 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -29,6 +29,7 @@
 #include "pmksa_cache_auth.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "wps_hostapd.h"
 #include "ieee802_1x.h"
 
 
@@ -96,12 +97,13 @@
 	}
 
 	if (res && errno != ENOENT) {
-		printf("Could not set station " MACSTR " flags for kernel "
-		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
+			   " flags for kernel driver (errno=%d).",
+			   MAC2STR(sta->addr), errno);
 	}
 
 	if (authorized) {
-		os_get_time(&sta->connected_time);
+		os_get_reltime(&sta->connected_time);
 		accounting_sta_start(hapd, sta);
 	}
 }
@@ -452,7 +454,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
 			     sm->radius_identifier);
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return;
 	}
 
@@ -461,7 +463,7 @@
 	if (sm->identity &&
 	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
 				 sm->identity, sm->identity_len)) {
-		printf("Could not add User-Name\n");
+		wpa_printf(MSG_INFO, "Could not add User-Name");
 		goto fail;
 	}
 
@@ -475,12 +477,12 @@
 	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
 					    RADIUS_ATTR_FRAMED_MTU) &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
-		printf("Could not add Framed-MTU\n");
+		wpa_printf(MSG_INFO, "Could not add Framed-MTU");
 		goto fail;
 	}
 
 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
-		printf("Could not add EAP-Message\n");
+		wpa_printf(MSG_INFO, "Could not add EAP-Message");
 		goto fail;
 	}
 
@@ -492,8 +494,7 @@
 		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
 					       RADIUS_ATTR_STATE);
 		if (res < 0) {
-			printf("Could not copy State attribute from previous "
-			       "Access-Challenge\n");
+			wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
 			goto fail;
 		}
 		if (res > 0) {
@@ -543,7 +544,7 @@
 	data = (u8 *) (eap + 1);
 
 	if (len < sizeof(*eap) + 1) {
-		printf("handle_eap_response: too short response data\n");
+		wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
 		return;
 	}
 
@@ -571,7 +572,7 @@
 	u16 eap_len;
 
 	if (len < sizeof(*eap)) {
-		printf("   too short EAP packet\n");
+		wpa_printf(MSG_INFO, "   too short EAP packet");
 		return;
 	}
 
@@ -664,7 +665,7 @@
 	}
 
 	if (len < sizeof(*hdr)) {
-		printf("   too short IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   too short IEEE 802.1X packet");
 		return;
 	}
 
@@ -674,7 +675,7 @@
 		   hdr->version, hdr->type, datalen);
 
 	if (len - sizeof(*hdr) < datalen) {
-		printf("   frame too short for this IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   frame too short for this IEEE 802.1X packet");
 		if (sta->eapol_sm)
 			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
 		return;
@@ -1276,15 +1277,14 @@
 			   "EAP-Message");
 	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
 				     req, 1)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Message-Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
 	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
 	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
 	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
@@ -1448,7 +1448,7 @@
 	if (eapol->default_wep_key == NULL ||
 	    random_get_bytes(eapol->default_wep_key,
 			     hapd->conf->default_wep_key_len)) {
-		printf("Could not generate random WEP key.\n");
+		wpa_printf(MSG_INFO, "Could not generate random WEP key");
 		os_free(eapol->default_wep_key);
 		eapol->default_wep_key = NULL;
 		return -1;
@@ -1952,7 +1952,9 @@
 {
 	int len = 0, ret;
 	struct eapol_state_machine *sm = sta->eapol_sm;
-	struct os_time t;
+	struct os_reltime diff;
+	const char *name1;
+	const char *name2;
 
 	if (sm == NULL)
 		return 0;
@@ -2067,7 +2069,7 @@
 	len += ret;
 
 	/* dot1xAuthSessionStatsTable */
-	os_get_time(&t);
+	os_reltime_age(&sta->acct_session_start, &diff);
 	ret = os_snprintf(buf + len, buflen - len,
 			  /* TODO: dot1xAuthSessionOctetsRx */
 			  /* TODO: dot1xAuthSessionOctetsTx */
@@ -2082,12 +2084,25 @@
 			  (wpa_key_mgmt_wpa_ieee8021x(
 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
 			  1 : 2,
-			  (unsigned int) (t.sec - sta->acct_session_start),
+			  (unsigned int) diff.sec,
 			  sm->identity);
 	if (ret < 0 || (size_t) ret >= buflen - len)
 		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 : "");
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
 	return len;
 }
 
@@ -2127,12 +2142,8 @@
 		 * driver reorder operations.
 		 */
 		os_sleep(0, 10000);
-#ifndef ANDROID_P2P
-		/* We need not do this for driver. For AP-SME flags if we send this disassoc,
-		  * the p2p_client is gettig disassoc after it has completed the assoc
-		  */
 		ap_sta_disconnect(hapd, sta, sta->addr,
 				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
-#endif
+		hostapd_wps_eap_completed(hapd);
 	}
 }
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 40972e9..4720b59 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -91,9 +91,9 @@
 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 {
 	struct rsn_pmksa_cache *pmksa = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
 		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
 			   MACSTR, MAC2STR(pmksa->pmksa->spa));
@@ -107,12 +107,12 @@
 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
 {
 	int sec;
-	struct os_time now;
+	struct os_reltime now;
 
 	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
 	if (pmksa->pmksa == NULL)
 		return;
-	os_get_time(&now);
+	os_get_reltime(&now);
 	sec = pmksa->pmksa->expiration - now.sec;
 	if (sec < 0)
 		sec = 0;
@@ -241,7 +241,7 @@
 		struct eapol_state_machine *eapol, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry, *pos;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (pmk_len > PMK_LEN)
 		return NULL;
@@ -253,7 +253,7 @@
 	entry->pmk_len = pmk_len;
 	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
 		  wpa_key_mgmt_sha256(akmp));
-	os_get_time(&now);
+	os_get_reltime(&now);
 	entry->expiration = now.sec;
 	if (session_timeout > 0)
 		entry->expiration += session_timeout;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 6704c09..24e764d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -15,7 +15,6 @@
 #include "common/sae.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
-#include "drivers/driver.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
 #include "accounting.h"
@@ -232,7 +231,8 @@
 	wpa_auth_sta_deinit(sta->wpa_sm);
 	rsn_preauth_free_station(hapd, sta);
 #ifndef CONFIG_NO_RADIUS
-	radius_client_flush_auth(hapd->radius, sta->addr);
+	if (hapd->radius)
+		radius_client_flush_auth(hapd->radius, sta->addr);
 #endif /* CONFIG_NO_RADIUS */
 
 	os_free(sta->last_assoc_req);
@@ -261,6 +261,7 @@
 	wpabuf_free(sta->hs20_ie);
 
 	os_free(sta->ht_capabilities);
+	os_free(sta->vht_capabilities);
 	hostapd_free_psk_list(sta->psk);
 	os_free(sta->identity);
 	os_free(sta->radius_cui);
@@ -489,6 +490,18 @@
 }
 
 
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			      u32 session_timeout)
+{
+	if (eloop_replenish_timeout(session_timeout, 0,
+				    ap_handle_session_timer, hapd, sta) == 1) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "setting session timeout "
+			       "to %d seconds", session_timeout);
+	}
+}
+
+
 void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout)
 {
@@ -531,13 +544,16 @@
 	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
 	accounting_sta_get_id(hapd, sta);
 
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+			   __func__, MAC2STR(addr),
+			   hapd->conf->ap_max_inactivity);
+		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+				       ap_handle_timer, hapd, sta);
+	}
+
 	/* initialize STA info data */
-	wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
-		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
-		   __func__, MAC2STR(addr),
-		   hapd->conf->ap_max_inactivity);
-	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
-			       ap_handle_timer, hapd, sta);
 	os_memcpy(sta->addr, addr, ETH_ALEN);
 	sta->next = hapd->sta_list;
 	hapd->sta_list = sta;
@@ -808,9 +824,9 @@
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	u32 tu;
-	struct os_time now, passed;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
+	struct os_reltime now, passed;
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &sta->sa_query_start, &passed);
 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
 	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
 		hostapd_logger(hapd, sta->addr,
@@ -847,7 +863,7 @@
 		return;
 	if (sta->sa_query_count == 0) {
 		/* Starting a new SA Query procedure */
-		os_get_time(&sta->sa_query_start);
+		os_get_reltime(&sta->sa_query_start);
 	}
 	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
 	sta->sa_query_trans_id = nbuf;
@@ -892,6 +908,7 @@
 	char buf[100];
 #ifdef CONFIG_P2P
 	u8 addr[ETH_ALEN];
+	u8 ip_addr_buf[4];
 #endif /* CONFIG_P2P */
 
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
@@ -913,12 +930,25 @@
 		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
 
 	if (authorized) {
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s", buf);
+		char ip_addr[100];
+		ip_addr[0] = '\0';
+#ifdef CONFIG_P2P
+		if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
+			os_snprintf(ip_addr, sizeof(ip_addr),
+				    " ip_addr=%u.%u.%u.%u",
+				    ip_addr_buf[0], ip_addr_buf[1],
+				    ip_addr_buf[2], ip_addr_buf[3]);
+		}
+#endif /* CONFIG_P2P */
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
+			buf, ip_addr);
 
 		if (hapd->msg_ctx_parent &&
 		    hapd->msg_ctx_parent != hapd->msg_ctx)
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
-					  AP_STA_CONNECTED "%s", buf);
+					  AP_STA_CONNECTED "%s%s",
+					  buf, ip_addr);
 
 		sta->flags |= WLAN_STA_AUTHORIZED;
 	} else {
@@ -995,3 +1025,33 @@
 	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
 	ap_sta_disassoc_cb_timeout(hapd, sta);
 }
+
+
+int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
+{
+	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",
+			  (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+			  (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+			  (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
+			  (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+			   ""),
+			  (flags & WLAN_STA_SHORT_PREAMBLE ?
+			   "[SHORT_PREAMBLE]" : ""),
+			  (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+			  (flags & WLAN_STA_WMM ? "[WMM]" : ""),
+			  (flags & WLAN_STA_MFP ? "[MFP]" : ""),
+			  (flags & WLAN_STA_WPS ? "[WPS]" : ""),
+			  (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+			  (flags & WLAN_STA_WDS ? "[WDS]" : ""),
+			  (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+			  (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
+			  (flags & WLAN_STA_GAS ? "[GAS]" : ""),
+			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
+			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
+			   "[WNM_SLEEP_MODE]" : ""));
+
+	return res;
+}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index e5b5069..240b926 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -12,9 +12,6 @@
 /* STA flags */
 #define WLAN_STA_AUTH BIT(0)
 #define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3)
-#define WLAN_STA_PERM BIT(4)
 #define WLAN_STA_AUTHORIZED BIT(5)
 #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
 #define WLAN_STA_SHORT_PREAMBLE BIT(7)
@@ -29,6 +26,8 @@
 #define WLAN_STA_WPS2 BIT(16)
 #define WLAN_STA_GAS BIT(17)
 #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_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -57,6 +56,7 @@
 	unsigned int no_ht_set:1;
 	unsigned int ht_20mhz_set:1;
 	unsigned int no_p2p_set:1;
+	unsigned int qos_map_enabled:1;
 
 	u16 auth_alg;
 	u8 previous_ap[6];
@@ -77,7 +77,7 @@
 
 	u32 acct_session_id_hi;
 	u32 acct_session_id_lo;
-	time_t acct_session_start;
+	struct os_reltime acct_session_start;
 	int acct_session_started;
 	int acct_terminate_cause; /* Acct-Terminate-Cause */
 	int acct_interim_interval; /* Acct-Interim-Interval */
@@ -104,6 +104,7 @@
 
 	struct ieee80211_ht_capabilities *ht_capabilities;
 	struct ieee80211_vht_capabilities *vht_capabilities;
+	u8 vht_opmode;
 
 #ifdef CONFIG_IEEE80211W
 	int sa_query_count; /* number of pending SA Query requests;
@@ -112,7 +113,7 @@
 	u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
 				* sa_query_count octets of pending SA Query
 				* transaction identifiers */
-	struct os_time sa_query_start;
+	struct os_reltime sa_query_start;
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_INTERWORKING
@@ -125,7 +126,7 @@
 	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
 
-	struct os_time connected_time;
+	struct os_reltime connected_time;
 
 #ifdef CONFIG_SAE
 	struct sae_data *sae;
@@ -161,6 +162,8 @@
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_free_stas(struct hostapd_data *hapd);
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			      u32 session_timeout);
 void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout);
 void ap_sta_no_session_timeout(struct hostapd_data *hapd,
@@ -192,4 +195,6 @@
 void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
 
+int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+
 #endif /* STA_INFO_H */
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 4a2ea06..4725e2b 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -68,7 +68,7 @@
 
 int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
 {
-	struct os_time now;
+	struct os_reltime now;
 	int ret = 0;
 
 	if (addr && local) {
@@ -89,8 +89,8 @@
 		}
 	}
 
-	os_get_time(&now);
-	if (now.sec > hapd->michael_mic_failure + 60) {
+	os_get_reltime(&now);
+	if (os_reltime_expired(&now, &hapd->michael_mic_failure, 60)) {
 		hapd->michael_mic_failures = 1;
 	} else {
 		hapd->michael_mic_failures++;
@@ -99,7 +99,7 @@
 			ret = 1;
 		}
 	}
-	hapd->michael_mic_failure = now.sec;
+	hapd->michael_mic_failure = now;
 
 	return ret;
 }
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 746af40..509e557 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -4,14 +4,8 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -1021,6 +1015,7 @@
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+	hapd->full_dynamic_vlan = NULL;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 }
 
diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h
index 382d5de..781eaac 100644
--- a/src/ap/vlan_init.h
+++ b/src/ap/vlan_init.h
@@ -3,14 +3,8 @@
  * Copyright 2003, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef VLAN_INIT_H
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index d21c82f..6d4177c 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -4,14 +4,8 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -157,7 +151,7 @@
 	len = ((u8 *) (t + 1)) - buf;
 
 	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
-		perror("wmm_send_action: send");
+		wpa_printf(MSG_INFO, "wmm_send_action: send failed");
 }
 
 
diff --git a/src/ap/wmm.h b/src/ap/wmm.h
index 96b04e8..b70b863 100644
--- a/src/ap/wmm.h
+++ b/src/ap/wmm.h
@@ -3,14 +3,8 @@
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef WME_H
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 54a6b85..8e5bdcb 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - WNM
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * 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 "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
@@ -72,7 +73,7 @@
 	wnmsleep_ie.len = wnmsleep_ie_len - 2;
 	wnmsleep_ie.action_type = action_type;
 	wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
-	wnmsleep_ie.intval = intval;
+	wnmsleep_ie.intval = host_to_le16(intval);
 
 	/* TFS IE(s) */
 	wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
@@ -154,6 +155,7 @@
 		 */
 		if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
 		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
+			sta->flags |= WLAN_STA_WNM_SLEEP_MODE;
 			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
 					     addr, NULL, NULL);
 			wpa_set_wnmsleep(sta->wpa_sm, 1);
@@ -167,6 +169,7 @@
 		     wnmsleep_ie.status ==
 		     WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
 		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
+			sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
 			wpa_set_wnmsleep(sta->wpa_sm, 0);
 			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
 					     addr, NULL, NULL);
@@ -233,7 +236,7 @@
 
 	ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
 				      wnmsleep_ie->action_type,
-				      wnmsleep_ie->intval);
+				      le_to_host16(wnmsleep_ie->intval));
 
 	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
 		/* clear the tfs after sending the resp frame */
@@ -243,29 +246,263 @@
 }
 
 
-int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
-				struct rx_action *action)
+static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
+						  const u8 *addr,
+						  u8 dialog_token,
+						  const char *url)
 {
-	if (action->len < 1 || action->data == NULL)
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len, len;
+	u8 *pos;
+	int res;
+
+	if (url)
+		url_len = os_strlen(url);
+	else
+		url_len = 0;
+
+	mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+	if (mgmt == NULL)
+		return -1;
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
+	mgmt->u.action.u.bss_tm_req.req_mode = 0;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 1;
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+	if (url) {
+		*pos++ += url_len;
+		os_memcpy(pos, url, url_len);
+		pos += url_len;
+	}
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
+		   MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
+		   "validity_interval=%u",
+		   MAC2STR(addr), dialog_token,
+		   mgmt->u.action.u.bss_tm_req.req_mode,
+		   le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer),
+		   mgmt->u.action.u.bss_tm_req.validity_interval);
+
+	len = pos - &mgmt->u.action.category;
+	res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+				      mgmt->da, &mgmt->u.action.category, len);
+	os_free(mgmt);
+	return res;
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
+					       const u8 *addr, const u8 *frm,
+					       size_t len)
+{
+	u8 dialog_token, reason;
+	const u8 *pos, *end;
+
+	if (len < 2) {
+		wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
+			   MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	pos = frm;
+	end = pos + len;
+	dialog_token = *pos++;
+	reason = *pos++;
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from "
+		   MACSTR " dialog_token=%u reason=%u",
+		   MAC2STR(addr), dialog_token, reason);
+
+	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
+		    pos, end - pos);
+
+	ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
+					      const u8 *addr, const u8 *frm,
+					      size_t len)
+{
+	u8 dialog_token, status_code, bss_termination_delay;
+	const u8 *pos, *end;
+
+	if (len < 3) {
+		wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
+			   MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	pos = frm;
+	end = pos + len;
+	dialog_token = *pos++;
+	status_code = *pos++;
+	bss_termination_delay = *pos++;
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from "
+		   MACSTR " dialog_token=%u status_code=%u "
+		   "bss_termination_delay=%u", MAC2STR(addr), dialog_token,
+		   status_code, bss_termination_delay);
+
+	if (status_code == WNM_BSS_TM_ACCEPT) {
+		if (end - pos < ETH_ALEN) {
+			wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
+			   MAC2STR(pos));
+		pos += ETH_ALEN;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
+		    pos, end - pos);
+}
+
+
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+				const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	u8 action;
+	const u8 *payload;
+	size_t plen;
+
+	if (len < IEEE80211_HDRLEN + 2)
 		return -1;
 
-	switch (action->data[0]) {
+	payload = &mgmt->u.action.category;
+	payload++;
+	action = *payload++;
+	plen = (((const u8 *) mgmt) + len) - payload;
+
+	switch (action) {
 	case WNM_BSS_TRANS_MGMT_QUERY:
-		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
-		/* TODO */
-		return -1;
+		ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
+						   plen);
+		return 0;
 	case WNM_BSS_TRANS_MGMT_RESP:
-		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
-			   "Response");
-		/* TODO */
-		return -1;
+		ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
+						  plen);
+		return 0;
 	case WNM_SLEEP_MODE_REQ:
-		ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
-					   action->len - 1);
+		ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
 		return 0;
 	}
 
 	wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
-		   action->data[0], MAC2STR(action->sa));
+		   action, MAC2STR(mgmt->sa));
 	return -1;
 }
+
+
+int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
+			       struct sta_info *sta, int disassoc_timer)
+{
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer =
+		host_to_le16(disassoc_timer);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
+		   MACSTR, disassoc_timer, MAC2STR(sta->addr));
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
+				   struct sta_info *sta, const char *url,
+				   int disassoc_timer)
+{
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len;
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
+		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer =
+		host_to_le16(disassoc_timer);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	/* Session Information URL */
+	url_len = os_strlen(url);
+	if (url_len > 255)
+		return -1;
+	*pos++ = url_len;
+	os_memcpy(pos, url, url_len);
+	pos += url_len;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	/* send disassociation frame after time-out */
+	if (disassoc_timer) {
+		int timeout, beacon_int;
+
+		/*
+		 * Prevent STA from reconnecting using cached PMKSA to force
+		 * full authentication with the authentication server (which may
+		 * decide to reject the connection),
+		 */
+		wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+
+		beacon_int = hapd->iconf->beacon_int;
+		if (beacon_int < 1)
+			beacon_int = 100; /* best guess */
+		/* Calculate timeout in ms based on beacon_int in TU */
+		timeout = disassoc_timer * beacon_int * 128 / 125;
+		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+			   " set to %d ms", MAC2STR(sta->addr), timeout);
+
+		sta->timeout_next = STA_DISASSOC_FROM_CLI;
+		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+		eloop_register_timeout(timeout / 1000,
+				       timeout % 1000 * 1000,
+				       ap_handle_timer, hapd, sta);
+	}
+
+	return 0;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index f05726e..eeaf5ec 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11v WNM related functions and structures
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,9 +9,14 @@
 #ifndef WNM_AP_H
 #define WNM_AP_H
 
-struct rx_action;
+struct sta_info;
 
 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
-				struct rx_action *action);
+				const struct ieee80211_mgmt *mgmt, size_t len);
+int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
+			       struct sta_info *sta, int disassoc_timer);
+int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
+				   struct sta_info *sta, const char *url,
+				   int disassoc_timer);
 
 #endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0286c5b..707a63f 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/state_machine.h"
+#include "utils/bitfield.h"
 #include "common/ieee802_11_defs.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
@@ -424,6 +425,17 @@
 				       wpa_rekey_gtk, wpa_auth, NULL);
 	}
 
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(conf->ip_addr_start)) {
+		int count = WPA_GET_BE32(conf->ip_addr_end) -
+			WPA_GET_BE32(conf->ip_addr_start) + 1;
+		if (count > 1000)
+			count = 1000;
+		if (count > 0)
+			wpa_auth->ip_pool = bitfield_alloc(count);
+	}
+#endif /* CONFIG_P2P */
+
 	return wpa_auth;
 }
 
@@ -437,6 +449,8 @@
 	wpa_group_sm_step(wpa_auth, group);
 	group->GInit = FALSE;
 	wpa_group_sm_step(wpa_auth, group);
+	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+		return -1;
 	return 0;
 }
 
@@ -464,6 +478,11 @@
 	wpa_auth->ft_pmk_cache = NULL;
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_P2P
+	bitfield_free(wpa_auth->ip_pool);
+#endif /* CONFIG_P2P */
+
+
 	os_free(wpa_auth->wpa_ie);
 
 	group = wpa_auth->group;
@@ -516,6 +535,9 @@
 {
 	struct wpa_state_machine *sm;
 
+	if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+		return NULL;
+
 	sm = os_zalloc(sizeof(struct wpa_state_machine));
 	if (sm == NULL)
 		return NULL;
@@ -578,6 +600,19 @@
 
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr)) {
+		u32 start;
+		wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
+			   "address %u.%u.%u.%u from " MACSTR,
+			   sm->ip_addr[0], sm->ip_addr[1],
+			   sm->ip_addr[2], sm->ip_addr[3],
+			   MAC2STR(sm->addr));
+		start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
+		bitfield_clear(sm->wpa_auth->ip_pool,
+			       WPA_GET_BE32(sm->ip_addr) - start);
+	}
+#endif /* CONFIG_P2P */
 	if (sm->GUpdateStationKeys) {
 		sm->group->GKeyDoneStations--;
 		sm->GUpdateStationKeys = FALSE;
@@ -995,6 +1030,26 @@
 			return;
 		}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+		if (kde.ip_addr_req && kde.ip_addr_req[0] &&
+		    wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
+			int idx;
+			wpa_printf(MSG_DEBUG, "P2P: IP address requested in "
+				   "EAPOL-Key exchange");
+			idx = bitfield_get_first_zero(wpa_auth->ip_pool);
+			if (idx >= 0) {
+				u32 start = WPA_GET_BE32(wpa_auth->conf.
+							 ip_addr_start);
+				bitfield_set(wpa_auth->ip_pool, idx);
+				WPA_PUT_BE32(sm->ip_addr, start + idx);
+				wpa_printf(MSG_DEBUG, "P2P: Assigned IP "
+					   "address %u.%u.%u.%u to " MACSTR,
+					   sm->ip_addr[0], sm->ip_addr[1],
+					   sm->ip_addr[2], sm->ip_addr[3],
+					   MAC2STR(sm->addr));
+			}
+		}
+#endif /* CONFIG_P2P */
 		break;
 	case PAIRWISE_4:
 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1863,6 +1918,7 @@
 {
 	struct wpa_igtk_kde igtk;
 	struct wpa_group *gsm = sm->group;
+	u8 rsc[WPA_KEY_RSC_LEN];
 
 	if (!sm->mgmt_frame_prot)
 		return pos;
@@ -1870,8 +1926,10 @@
 	igtk.keyid[0] = gsm->GN_igtk;
 	igtk.keyid[1] = 0;
 	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
-	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
 		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	else
+		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
 	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
 	if (sm->wpa_auth->conf.disable_gtk) {
 		/*
@@ -1987,6 +2045,10 @@
 		kde_len += 300; /* FTIE + 2 * TIE */
 	}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr) > 0)
+		kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
+#endif /* CONFIG_P2P */
 	kde = os_malloc(kde_len);
 	if (kde == NULL)
 		return;
@@ -2048,6 +2110,16 @@
 		pos += 4;
 	}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr) > 0) {
+		u8 addr[3 * 4];
+		os_memcpy(addr, sm->ip_addr, 4);
+		os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
+		os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+		pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
+				  addr, sizeof(addr), NULL, 0);
+	}
+#endif /* CONFIG_P2P */
 
 	wpa_send_eapol(sm->wpa_auth, sm,
 		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
@@ -2449,7 +2521,7 @@
 /* update GTK when exiting WNM-Sleep Mode */
 void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
 {
-	if (sm->is_wnmsleep)
+	if (sm == NULL || sm->is_wnmsleep)
 		return;
 
 	wpa_group_update_sta(sm, NULL);
@@ -2458,7 +2530,8 @@
 
 void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
 {
-	sm->is_wnmsleep = !!flag;
+	if (sm)
+		sm->is_wnmsleep = !!flag;
 }
 
 
@@ -2584,6 +2657,29 @@
 }
 
 
+static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
+{
+	if (sm->group == ctx) {
+		wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
+			   " for discconnection due to fatal failure",
+			   MAC2STR(sm->addr));
+		sm->Disconnect = TRUE;
+	}
+
+	return 0;
+}
+
+
+static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
+				    struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
+	wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
+}
+
+
 static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
 				 struct wpa_group *group)
 {
@@ -2592,8 +2688,10 @@
 	group->changed = TRUE;
 	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
 
-	if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+	if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
+		wpa_group_fatal_failure(wpa_auth, group);
 		return -1;
+	}
 
 	return 0;
 }
@@ -2604,6 +2702,8 @@
 {
 	if (group->GInit) {
 		wpa_group_gtk_init(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) {
+		/* Do not allow group operations */
 	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
 		   group->GTKAuthenticator) {
 		wpa_group_setkeysdone(wpa_auth, group);
@@ -3012,6 +3112,9 @@
 	if (sm->group == group)
 		return 0;
 
+	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+		return -1;
+
 	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
 		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
 
@@ -3056,3 +3159,22 @@
 		return 0;
 	return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
 }
+
+
+int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
+}
+
+
+#ifdef CONFIG_P2P
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
+{
+	if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+		return -1;
+	os_memcpy(addr, sm->ip_addr, 4);
+	return 0;
+}
+#endif /* CONFIG_P2P */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 47503d0..bc3dec4 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -163,6 +163,12 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	double corrupt_gtk_rekey_mic_probability;
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+	u8 ip_addr_go[4];
+	u8 ip_addr_mask[4];
+	u8 ip_addr_start[4];
+	u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
 };
 
 typedef enum {
@@ -203,7 +209,7 @@
 	int (*send_ft_action)(void *ctx, const u8 *dst,
 			      const u8 *data, size_t data_len);
 	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
-                         size_t tspec_ielen);
+			 size_t tspec_ielen);
 #endif /* CONFIG_IEEE80211R */
 };
 
@@ -295,5 +301,8 @@
 int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 
 int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
+
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
 
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 29d9d29..c22c4cc 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -57,7 +57,7 @@
 			    u8 *tspec_ie, size_t tspec_ielen)
 {
 	if (wpa_auth->cb.add_tspec == NULL) {
-	        wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+		wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
 		return -1;
 	}
 	return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
@@ -570,8 +570,8 @@
 			else {
 				/* TSPEC accepted; include updated TSPEC in
 				 * response */
-		                rdie->descr_count = 1;
-	                        pos += sizeof(*tspec);
+				rdie->descr_count = 1;
+				pos += sizeof(*tspec);
 			}
 			return pos;
 		}
@@ -633,8 +633,7 @@
 
 	conf = &sm->wpa_auth->conf;
 
-	if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+	if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
 		return pos;
 
 	end = pos + max_len;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index d977b42..5af1495 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -15,7 +15,6 @@
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eap_server/eap.h"
 #include "l2_packet/l2_packet.h"
-#include "drivers/driver.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "preauth_auth.h"
@@ -79,6 +78,12 @@
 	wconf->corrupt_gtk_rekey_mic_probability =
 		iconf->corrupt_gtk_rekey_mic_probability;
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+	os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
+	os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4);
+	os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4);
+	os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -618,5 +623,6 @@
 
 #ifdef CONFIG_IEEE80211R
 	l2_packet_deinit(hapd->l2);
+	hapd->l2 = NULL;
 #endif /* CONFIG_IEEE80211R */
 }
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 12e59bc..fcd5878 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -121,6 +121,10 @@
 #endif /* CONFIG_IEEE80211R */
 
 	int pending_1_of_4_timeout;
+
+#ifdef CONFIG_P2P
+	u8 ip_addr[4];
+#endif /* CONFIG_P2P */
 };
 
 
@@ -139,7 +143,8 @@
 
 	enum {
 		WPA_GROUP_GTK_INIT = 0,
-		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE,
+		WPA_GROUP_FATAL_FAILURE
 	} wpa_group_state;
 
 	u8 GMK[WPA_GMK_LEN];
@@ -184,6 +189,10 @@
 
 	struct rsn_pmksa_cache *pmksa;
 	struct wpa_ft_pmk_cache *ft_pmk_cache;
+
+#ifdef CONFIG_P2P
+	struct bitfield *ip_pool;
+#endif /* CONFIG_P2P */
 };
 
 
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index cdfcca1..274f4d6 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -708,6 +708,25 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+
+	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG,
+			    "WPA: IP Address Allocation in EAPOL-Key",
+			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+#endif /* CONFIG_P2P */
+
 	return 0;
 }
 
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index 4999139..f945882 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -39,6 +39,10 @@
 	const u8 *ftie;
 	size_t ftie_len;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	const u8 *ip_addr_req;
+	const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
 };
 
 int wpa_parse_kde_ies(const u8 *buf, size_t len,
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index eb300f1..3a40125 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -287,6 +287,20 @@
 }
 
 
+void hostapd_wps_eap_completed(struct hostapd_data *hapd)
+{
+	/*
+	 * Reduce race condition of the station trying to reconnect immediately
+	 * after AP reconfiguration through WPS by rescheduling the reload
+	 * timeout to happen after EAP completion rather than the originally
+	 * scheduled 100 ms after new configuration became known.
+	 */
+	if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) ==
+	    1)
+		wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload");
+}
+
+
 static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
 			      size_t attr_len)
 {
@@ -457,6 +471,8 @@
 	hapd->wps->ssid_len = cred->ssid_len;
 	hapd->wps->encr_types = cred->encr_type;
 	hapd->wps->auth_types = cred->auth_type;
+	hapd->wps->ap_encr_type = cred->encr_type;
+	hapd->wps->ap_auth_type = cred->auth_type;
 	if (cred->key_len == 0) {
 		os_free(hapd->wps->network_key);
 		hapd->wps->network_key = NULL;
@@ -1132,6 +1148,8 @@
 		wps->psk_set = 1;
 	}
 
+	wps->ap_auth_type = wps->auth_types;
+	wps->ap_encr_type = wps->encr_types;
 	if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
 		/* Override parameters to enable security by default */
 		wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
@@ -1211,6 +1229,7 @@
 static void hostapd_wps_nfc_clear(struct wps_context *wps)
 {
 #ifdef CONFIG_WPS_NFC
+	wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
 	wps->ap_nfc_dev_pw_id = 0;
 	wpabuf_free(wps->ap_nfc_dh_pubkey);
 	wps->ap_nfc_dh_pubkey = NULL;
@@ -1226,6 +1245,7 @@
 {
 	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
 	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL);
 	if (hapd->wps == NULL)
 		return;
 #ifdef CONFIG_WPS_UPNP
@@ -1459,6 +1479,16 @@
 		return 0;
 	}
 
+	if (!sta->eapol_sm) {
+		/*
+		 * This can happen, e.g., if an ER sends an extra message after
+		 * the station has disassociated (but not fully
+		 * deauthenticated).
+		 */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Matching STA did not have EAPOL state machine initialized");
+		return 0;
+	}
+
 	p = os_zalloc(sizeof(*p));
 	if (p == NULL)
 		return -1;
@@ -1768,7 +1798,8 @@
 	if (hapd->wps == NULL)
 		return NULL;
 
-	ret = wps_get_oob_cred(hapd->wps);
+	ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd),
+			       hapd->iconf->channel);
 	if (ndef && ret) {
 		struct wpabuf *tmp;
 		tmp = ndef_build_wifi(ret);
@@ -1784,11 +1815,136 @@
 
 struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
 {
+	struct wpabuf *ret;
+
+	if (hapd->wps == NULL)
+		return NULL;
+
+	if (hapd->conf->wps_nfc_dh_pubkey == NULL) {
+		struct wps_context *wps = hapd->wps;
+		if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey,
+				   &hapd->conf->wps_nfc_dh_privkey) < 0)
+			return NULL;
+		hostapd_wps_nfc_clear(wps);
+		wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+		wps->ap_nfc_dh_pubkey =
+			wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+		wps->ap_nfc_dh_privkey =
+			wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+		if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+			hostapd_wps_nfc_clear(wps);
+			return NULL;
+		}
+	}
+
+	ret = wps_build_nfc_handover_sel(hapd->wps,
+					 hapd->conf->wps_nfc_dh_pubkey,
+					 hapd->own_addr, hapd->iface->freq);
+
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+
+
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel)
+{
+	struct wpabuf *wps;
+	int ret = -1;
+	u16 wsc_len;
+	const u8 *pos;
+	struct wpabuf msg;
+	struct wps_parse_attr attr;
+	u16 dev_pw_id;
+
 	/*
-	 * Handover Select carrier record for WPS uses the same format as
-	 * configuration token.
+	 * Enrollee/station is always initiator of the NFC connection handover,
+	 * so use the request message here to find Enrollee public key hash.
 	 */
-	return hostapd_wps_nfc_config_token(hapd, ndef);
+	wps = ndef_parse_wifi(req);
+	if (wps == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+		   "payload from NFC connection handover");
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+	if (wpabuf_len(wps) < 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+			   "Message");
+		goto out;
+	}
+	pos = wpabuf_head(wps);
+	wsc_len = WPA_GET_BE16(pos);
+	if (wsc_len > wpabuf_len(wps) - 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+			   "in rt Wi-Fi Handover Request Message", wsc_len);
+		goto out;
+	}
+	pos += 2;
+
+	wpa_hexdump(MSG_DEBUG,
+		    "WPS: WSC attributes in Wi-Fi Handover Request Message",
+		    pos, wsc_len);
+	if (wsc_len < wpabuf_len(wps) - 2) {
+		wpa_hexdump(MSG_DEBUG,
+			    "WPS: Ignore extra data after WSC attributes",
+			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+	}
+
+	wpabuf_set(&msg, pos, wsc_len);
+	ret = wps_parse_msg(&msg, &attr);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+			   "Wi-Fi Handover Request Message");
+		goto out;
+	}
+
+	if (attr.oob_dev_password == NULL ||
+	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+			   "included in Wi-Fi Handover Request Message");
+		ret = -1;
+		goto out;
+	}
+
+	if (attr.uuid_e == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+			   "Handover Request Message");
+		ret = -1;
+		goto out;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+		    attr.oob_dev_password, attr.oob_dev_password_len);
+	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+				 WPS_OOB_PUBKEY_HASH_LEN);
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+			   "%u in Wi-Fi Handover Request Message", dev_pw_id);
+		ret = -1;
+		goto out;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+	ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar,
+					     attr.oob_dev_password,
+					     DEV_PW_NFC_CONNECTION_HANDOVER,
+					     NULL, 0, 1);
+
+out:
+	wpabuf_free(wps);
+	return ret;
 }
 
 
@@ -1823,6 +1979,9 @@
 		return -1;
 
 	hostapd_wps_nfc_clear(wps);
+	wpa_printf(MSG_DEBUG,
+		   "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
+		   hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
 	wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
 	wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
 	wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
@@ -1849,6 +2008,8 @@
 
 void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
 {
+	wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
+		   hapd->conf->iface);
 	hostapd_wps_nfc_clear(hapd->wps);
 }
 
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index a2c2cf0..204bd82 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -16,6 +16,7 @@
 int hostapd_init_wps_complete(struct hostapd_data *hapd);
 void hostapd_deinit_wps(struct hostapd_data *hapd);
 void hostapd_update_wps(struct hostapd_data *hapd);
+void hostapd_wps_eap_completed(struct hostapd_data *hapd);
 int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
 			const char *uuid, const char *pin, int timeout);
 int hostapd_wps_button_pushed(struct hostapd_data *hapd,
@@ -36,6 +37,9 @@
 struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
 					     int ndef);
 struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel);
 struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
 int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
 void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
@@ -61,6 +65,10 @@
 {
 }
 
+static inline void hostapd_wps_eap_completed(struct hostapd_data *hapd)
+{
+}
+
 static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
 					  const u8 *addr,
 					  char *buf, size_t buflen)
diff --git a/src/common/Makefile b/src/common/Makefile
index 9c41962..adfd3df 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/common/defs.h b/src/common/defs.h
index 281dd8a..4811e8e 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -23,11 +23,15 @@
 #define WPA_CIPHER_WEP104 BIT(2)
 #define WPA_CIPHER_TKIP BIT(3)
 #define WPA_CIPHER_CCMP BIT(4)
-#ifdef CONFIG_IEEE80211W
 #define WPA_CIPHER_AES_128_CMAC BIT(5)
-#endif /* CONFIG_IEEE80211W */
 #define WPA_CIPHER_GCMP BIT(6)
 #define WPA_CIPHER_SMS4 BIT(7)
+#define WPA_CIPHER_GCMP_256 BIT(8)
+#define WPA_CIPHER_CCMP_256 BIT(9)
+#define WPA_CIPHER_BIP_GMAC_128 BIT(11)
+#define WPA_CIPHER_BIP_GMAC_256 BIT(12)
+#define WPA_CIPHER_BIP_CMAC_256 BIT(13)
+#define WPA_CIPHER_GTK_NOT_USED BIT(14)
 
 #define WPA_KEY_MGMT_IEEE8021X BIT(0)
 #define WPA_KEY_MGMT_PSK BIT(1)
@@ -58,7 +62,8 @@
 	return !!(akm & (WPA_KEY_MGMT_PSK |
 			 WPA_KEY_MGMT_FT_PSK |
 			 WPA_KEY_MGMT_PSK_SHA256 |
-			 WPA_KEY_MGMT_SAE));
+			 WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
 }
 
 static inline int wpa_key_mgmt_ft(int akm)
@@ -83,7 +88,8 @@
 static inline int wpa_key_mgmt_wpa(int akm)
 {
 	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
-		wpa_key_mgmt_wpa_psk(akm);
+		wpa_key_mgmt_wpa_psk(akm) ||
+		wpa_key_mgmt_sae(akm);
 }
 
 static inline int wpa_key_mgmt_wpa_any(int akm)
@@ -117,41 +123,12 @@
 	WPA_ALG_PMK,
 	WPA_ALG_GCMP,
 	WPA_ALG_SMS4,
-	WPA_ALG_KRK
-};
-
-/**
- * enum wpa_cipher - Cipher suites
- */
-enum wpa_cipher {
-	CIPHER_NONE,
-	CIPHER_WEP40,
-	CIPHER_TKIP,
-	CIPHER_CCMP,
-	CIPHER_WEP104,
-	CIPHER_GCMP,
-	CIPHER_SMS4
-};
-
-/**
- * enum wpa_key_mgmt - Key management suites
- */
-enum wpa_key_mgmt {
-	KEY_MGMT_802_1X,
-	KEY_MGMT_PSK,
-	KEY_MGMT_NONE,
-	KEY_MGMT_802_1X_NO_WPA,
-	KEY_MGMT_WPA_NONE,
-	KEY_MGMT_FT_802_1X,
-	KEY_MGMT_FT_PSK,
-	KEY_MGMT_802_1X_SHA256,
-	KEY_MGMT_PSK_SHA256,
-	KEY_MGMT_WPS,
-	KEY_MGMT_SAE,
-	KEY_MGMT_FT_SAE,
-	KEY_MGMT_WAPI_PSK,
-	KEY_MGMT_WAPI_CERT,
-	KEY_MGMT_CCKM
+	WPA_ALG_KRK,
+	WPA_ALG_GCMP_256,
+	WPA_ALG_CCMP_256,
+	WPA_ALG_BIP_GMAC_128,
+	WPA_ALG_BIP_GMAC_256,
+	WPA_ALG_BIP_CMAC_256
 };
 
 /**
@@ -312,6 +289,7 @@
 	WPA_CTRL_REQ_EAP_PIN,
 	WPA_CTRL_REQ_EAP_OTP,
 	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	WPA_CTRL_REQ_SIM,
 	NUM_WPA_CTRL_REQS
 };
 
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index aab8ac6..50bdc01 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -189,25 +189,12 @@
 			elems->supp_rates = pos;
 			elems->supp_rates_len = elen;
 			break;
-		case WLAN_EID_FH_PARAMS:
-			elems->fh_params = pos;
-			elems->fh_params_len = elen;
-			break;
 		case WLAN_EID_DS_PARAMS:
 			elems->ds_params = pos;
 			elems->ds_params_len = elen;
 			break;
 		case WLAN_EID_CF_PARAMS:
-			elems->cf_params = pos;
-			elems->cf_params_len = elen;
-			break;
 		case WLAN_EID_TIM:
-			elems->tim = pos;
-			elems->tim_len = elen;
-			break;
-		case WLAN_EID_IBSS_PARAMS:
-			elems->ibss_params = pos;
-			elems->ibss_params_len = elen;
 			break;
 		case WLAN_EID_CHALLENGE:
 			elems->challenge = pos;
@@ -232,8 +219,6 @@
 			elems->rsn_ie_len = elen;
 			break;
 		case WLAN_EID_PWR_CAPABILITY:
-			elems->power_cap = pos;
-			elems->power_cap_len = elen;
 			break;
 		case WLAN_EID_SUPPORTED_CHANNELS:
 			elems->supp_channels = pos;
@@ -267,6 +252,11 @@
 			elems->vht_operation = pos;
 			elems->vht_operation_len = elen;
 			break;
+		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+			if (elen != 1)
+				break;
+			elems->vht_opmode_notif = pos;
+			break;
 		case WLAN_EID_LINK_ID:
 			if (elen < 18)
 				break;
@@ -276,6 +266,12 @@
 			elems->interworking = pos;
 			elems->interworking_len = elen;
 			break;
+		case WLAN_EID_QOS_MAP_SET:
+			if (elen < 16)
+				break;
+			elems->qos_map_set = pos;
+			elems->qos_map_set_len = elen;
+			break;
 		case WLAN_EID_EXT_CAPAB:
 			elems->ext_capab = pos;
 			elems->ext_capab_len = elen;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 68c6b96..4fb2e84 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -13,11 +13,7 @@
 struct ieee802_11_elems {
 	const u8 *ssid;
 	const u8 *supp_rates;
-	const u8 *fh_params;
 	const u8 *ds_params;
-	const u8 *cf_params;
-	const u8 *tim;
-	const u8 *ibss_params;
 	const u8 *challenge;
 	const u8 *erp_info;
 	const u8 *ext_supp_rates;
@@ -26,7 +22,6 @@
 	const u8 *wmm; /* WMM Information or Parameter Element */
 	const u8 *wmm_tspec;
 	const u8 *wps_ie;
-	const u8 *power_cap;
 	const u8 *supp_channels;
 	const u8 *mdie;
 	const u8 *ftie;
@@ -35,11 +30,13 @@
 	const u8 *ht_operation;
 	const u8 *vht_capabilities;
 	const u8 *vht_operation;
+	const u8 *vht_opmode_notif;
 	const u8 *vendor_ht_cap;
 	const u8 *p2p;
 	const u8 *wfd;
 	const u8 *link_id;
 	const u8 *interworking;
+	const u8 *qos_map_set;
 	const u8 *hs20;
 	const u8 *ext_capab;
 	const u8 *bss_max_idle_period;
@@ -47,11 +44,7 @@
 
 	u8 ssid_len;
 	u8 supp_rates_len;
-	u8 fh_params_len;
 	u8 ds_params_len;
-	u8 cf_params_len;
-	u8 tim_len;
-	u8 ibss_params_len;
 	u8 challenge_len;
 	u8 erp_info_len;
 	u8 ext_supp_rates_len;
@@ -60,7 +53,6 @@
 	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
 	u8 wmm_tspec_len;
 	u8 wps_ie_len;
-	u8 power_cap_len;
 	u8 supp_channels_len;
 	u8 mdie_len;
 	u8 ftie_len;
@@ -73,6 +65,7 @@
 	u8 p2p_len;
 	u8 wfd_len;
 	u8 interworking_len;
+	u8 qos_map_set_len;
 	u8 hs20_len;
 	u8 ext_capab_len;
 	u8 ssid_list_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 137c309..0e39caf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -161,6 +161,7 @@
 #define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
 #define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
 #define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
 #define WLAN_REASON_UNSPECIFIED 1
@@ -203,6 +204,7 @@
 #define WLAN_EID_TIM 5
 #define WLAN_EID_IBSS_PARAMS 6
 #define WLAN_EID_COUNTRY 7
+#define WLAN_EID_BSS_LOAD 11
 #define WLAN_EID_CHALLENGE 16
 /* EIDs defined by IEEE 802.11h - START */
 #define WLAN_EID_PWR_CONSTRAINT 32
@@ -225,6 +227,7 @@
 #define WLAN_EID_FAST_BSS_TRANSITION 55
 #define WLAN_EID_TIMEOUT_INTERVAL 56
 #define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
 #define WLAN_EID_WAPI 68
@@ -242,6 +245,7 @@
 #define WLAN_EID_LINK_ID 101
 #define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_QOS_MAP_SET 110
 #define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
 #define WLAN_EID_CCKM 156
@@ -267,6 +271,7 @@
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_PROTECTED_DUAL 9
 #define WLAN_ACTION_WNM 10
 #define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
@@ -282,6 +287,19 @@
 #define WLAN_PA_GAS_COMEBACK_RESP 13
 #define WLAN_TDLS_DISCOVERY_RESPONSE 14
 
+/* Protected Dual of Public Action frames */
+#define WLAN_PROT_DSE_ENABLEMENT 1
+#define WLAN_PROT_DSE_DEENABLEMENT 2
+#define WLAN_PROT_EXT_CSA 4
+#define WLAN_PROT_MEASUREMENT_REQ 5
+#define WLAN_PROT_MEASUREMENT_REPORT 6
+#define WLAN_PROT_DSE_POWER_CONSTRAINT 8
+#define WLAN_PROT_VENDOR_SPECIFIC 9
+#define WLAN_PROT_GAS_INITIAL_REQ 10
+#define WLAN_PROT_GAS_INITIAL_RESP 11
+#define WLAN_PROT_GAS_COMEBACK_REQ 12
+#define WLAN_PROT_GAS_COMEBACK_RESP 13
+
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
 #define WLAN_SA_QUERY_RESPONSE 1
@@ -585,6 +603,17 @@
 } STRUCT_PACKED;
 
 
+struct ieee80211_obss_scan_parameters {
+	le16 scan_passive_dwell;
+	le16 scan_active_dwell;
+	le16 width_trigger_scan_interval;
+	le16 scan_passive_total_per_channel;
+	le16 scan_active_total_per_channel;
+	le16 channel_transition_delay_factor;
+	le16 scan_activity_threshold;
+} STRUCT_PACKED;
+
+
 struct ieee80211_vht_capabilities {
 	le32 vht_capabilities_info;
 	struct {
@@ -702,8 +731,10 @@
 /* VHT Defines */
 #define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
 #define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK                ((u32) BIT(0) | BIT(1))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_SUPP_CHAN_WIDTH_MASK                ((u32) BIT(2) | BIT(3))
 #define VHT_CAP_RXLDPC                              ((u32) BIT(4))
 #define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
 #define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
@@ -712,20 +743,34 @@
 #define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
 #define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
 #define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_RXSTBC_MASK                         ((u32) BIT(8) | BIT(9) | \
+							   BIT(10))
 #define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
 #define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
-#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
-#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_BEAMFORMEE_STS_MAX                  ((u32) BIT(13) | \
+							   BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_OFFSET               13
+#define VHT_CAP_SOUNDING_DIMENSION_MAX              ((u32) BIT(16) | \
+							   BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_OFFSET           16
 #define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
 #define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
 #define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
 #define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
-#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23) | \
+							   BIT(24) | BIT(25))
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
 #define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
 #define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
 
+#define VHT_OPMODE_CHANNEL_WIDTH_MASK		    ((u8) BIT(0) | BIT(1))
+#define VHT_OPMODE_CHANNEL_RxNSS_MASK		    ((u8) BIT(4) | BIT(5) | \
+						     BIT(6))
+#define VHT_OPMODE_NOTIF_RX_NSS_SHIFT		    4
+
+#define VHT_RX_NSS_MAX_STREAMS			    8
+
 /* VHT channel widths */
 #define VHT_CHANWIDTH_USE_HT	0
 #define VHT_CHANWIDTH_80MHZ	1
@@ -888,6 +933,7 @@
 	P2P_ATTR_INTERFACE = 16,
 	P2P_ATTR_OPERATING_CHANNEL = 17,
 	P2P_ATTR_INVITATION_FLAGS = 18,
+	P2P_ATTR_OOB_GO_NEG_CHANNEL = 19,
 	P2P_ATTR_VENDOR_SPECIFIC = 221
 };
 
@@ -909,6 +955,7 @@
 #define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
 #define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
 #define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
 
 /* Invitation Flags */
 #define P2P_INVITATION_FLAGS_TYPE BIT(0)
@@ -933,6 +980,12 @@
 	P2P_SC_FAIL_REJECTED_BY_USER = 11,
 };
 
+enum p2p_role_indication {
+	P2P_DEVICE_NOT_IN_GROUP = 0x00,
+	P2P_CLIENT_IN_A_GROUP = 0x01,
+	P2P_GO_IN_A_GROUP = 0x02,
+};
+
 #define P2P_WILDCARD_SSID "DIRECT-"
 #define P2P_WILDCARD_SSID_LEN 7
 
@@ -1002,6 +1055,11 @@
 #define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
 #define WLAN_CIPHER_SUITE_NO_GROUP_ADDR	0x000FAC07
 #define WLAN_CIPHER_SUITE_GCMP		0x000FAC08
+#define WLAN_CIPHER_SUITE_GCMP_256	0x000FAC09
+#define WLAN_CIPHER_SUITE_CCMP_256	0x000FAC0A
+#define WLAN_CIPHER_SUITE_BIP_GMAC_128	0x000FAC0B
+#define WLAN_CIPHER_SUITE_BIP_GMAC_256	0x000FAC0C
+#define WLAN_CIPHER_SUITE_BIP_CMAC_256	0x000FAC0D
 
 #define WLAN_CIPHER_SUITE_SMS4		0x00147201
 
@@ -1079,6 +1137,15 @@
 #define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
 #define WNM_NEIGHBOR_MULTIPLE_BSSID             71
 
+/* QoS action */
+enum qos_action {
+	QOS_ADDTS_REQ = 0,
+	QOS_ADDTS_RESP = 1,
+	QOS_DELTS = 2,
+	QOS_SCHEDULE = 3,
+	QOS_QOS_MAP_CONFIG = 4,
+};
+
 /* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
 #define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
 #define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
@@ -1126,4 +1193,8 @@
 	WNM_SLEEP_SUBELEM_IGTK = 1
 };
 
+/* Channel Switch modes (802.11h) */
+#define CHAN_SWITCH_MODE_ALLOW_TX	0
+#define CHAN_SWITCH_MODE_BLOCK_TX	1
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
new file mode 100644
index 0000000..0d83920
--- /dev/null
+++ b/src/common/qca-vendor.h
@@ -0,0 +1,51 @@
+/*
+ * Qualcomm Atheros OUI and vendor specific assignments
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef QCA_VENDOR_H
+#define QCA_VENDOR_H
+
+/*
+ * This file is a registry of identifier assignments from the Qualcomm Atheros
+ * OUI 00:13:74 for purposes other than MAC address assignment. New identifiers
+ * can be assigned through normal review process for changes to the upstream
+ * hostap.git repository.
+ */
+
+#define OUI_QCA 0x001374
+
+/**
+ * enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
+ *	ranges to avoid to reduce issues due to interference or internal
+ *	co-existence information in the driver. The event data structure is
+ *	defined in struct qca_avoid_freq_list.
+ */
+enum qca_nl80211_vendor_subcmds {
+	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
+	QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
+	/* subcmds 2..9 not yet allocated */
+	QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
+};
+
+
+struct qca_avoid_freq_range {
+	u32 start_freq;
+	u32 end_freq;
+} STRUCT_PACKED;
+
+struct qca_avoid_freq_list {
+	u32 count;
+	struct qca_avoid_freq_range range[0];
+} STRUCT_PACKED;
+
+#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index bce60a3..674cb65 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -503,6 +503,8 @@
 		       const u8 *password, size_t password_len,
 		       struct sae_data *sae)
 {
+	if (sae->tmp == NULL)
+		return -1;
 	if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
 					  password_len) < 0)
 		return -1;
@@ -634,7 +636,8 @@
 int sae_process_commit(struct sae_data *sae)
 {
 	u8 k[SAE_MAX_PRIME_LEN];
-	if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
+	if (sae->tmp == NULL ||
+	    (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
 	    (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
 	    sae_derive_keys(sae, k) < 0)
 		return -1;
@@ -646,6 +649,10 @@
 		      const struct wpabuf *token)
 {
 	u8 *pos;
+
+	if (sae->tmp == NULL)
+		return;
+
 	wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
 	if (token)
 		wpabuf_put_buf(buf, token);
@@ -678,7 +685,7 @@
 {
 	if (allowed_groups) {
 		int i;
-		for (i = 0; allowed_groups[i] >= 0; i++) {
+		for (i = 0; allowed_groups[i] > 0; i++) {
 			if (allowed_groups[i] == group)
 				break;
 		}
@@ -701,6 +708,11 @@
 		return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
 	}
 
+	if (sae->tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
 	if (sae->tmp->dh && !allowed_groups) {
 		wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
 			   "explicit configuration enabling it", group);
@@ -797,7 +809,7 @@
 
 	/* element x and y coordinates < p */
 	if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
-	    os_memcmp(pos + sae->tmp->prime_len + sae->tmp->prime_len, prime,
+	    os_memcmp(pos + sae->tmp->prime_len, prime,
 		      sae->tmp->prime_len) >= 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
 			   "element");
@@ -985,6 +997,9 @@
 {
 	const u8 *sc;
 
+	if (sae->tmp == NULL)
+		return;
+
 	/* Send-Confirm */
 	sc = wpabuf_put(buf, 0);
 	wpabuf_put_le16(buf, sae->send_confirm);
@@ -1016,6 +1031,11 @@
 
 	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
 
+	if (sae->tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
+		return -1;
+	}
+
 	if (sae->tmp->ec)
 		sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
 				   sae->tmp->peer_commit_element_ecc,
diff --git a/src/common/version.h b/src/common/version.h
index 2faa8c7..fb3b4f5 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.1-devel" VERSION_STR_POSTFIX
+#define VERSION_STR "2.2-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index c3afbfd..37b265d 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -353,6 +353,16 @@
 #endif /* CONFIG_IEEE80211W */
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
 		return WPA_CIPHER_GCMP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
+		return WPA_CIPHER_CCMP_256;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
+		return WPA_CIPHER_GCMP_256;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
+		return WPA_CIPHER_BIP_GMAC_128;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
+		return WPA_CIPHER_BIP_GMAC_256;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
+		return WPA_CIPHER_BIP_CMAC_256;
 	return 0;
 }
 
@@ -912,6 +922,12 @@
 		return "CCMP+TKIP";
 	case WPA_CIPHER_GCMP:
 		return "GCMP";
+	case WPA_CIPHER_GCMP_256:
+		return "GCMP-256";
+	case WPA_CIPHER_CCMP_256:
+		return "CCMP-256";
+	case WPA_CIPHER_GTK_NOT_USED:
+		return "GTK_NOT_USED";
 	default:
 		return "UNKNOWN";
 	}
@@ -1078,6 +1094,9 @@
 int wpa_cipher_key_len(int cipher)
 {
 	switch (cipher) {
+	case WPA_CIPHER_CCMP_256:
+	case WPA_CIPHER_GCMP_256:
+		return 32;
 	case WPA_CIPHER_CCMP:
 	case WPA_CIPHER_GCMP:
 		return 16;
@@ -1096,6 +1115,8 @@
 int wpa_cipher_rsc_len(int cipher)
 {
 	switch (cipher) {
+	case WPA_CIPHER_CCMP_256:
+	case WPA_CIPHER_GCMP_256:
 	case WPA_CIPHER_CCMP:
 	case WPA_CIPHER_GCMP:
 	case WPA_CIPHER_TKIP:
@@ -1112,6 +1133,10 @@
 int wpa_cipher_to_alg(int cipher)
 {
 	switch (cipher) {
+	case WPA_CIPHER_CCMP_256:
+		return WPA_ALG_CCMP_256;
+	case WPA_CIPHER_GCMP_256:
+		return WPA_ALG_GCMP_256;
 	case WPA_CIPHER_CCMP:
 		return WPA_ALG_CCMP;
 	case WPA_CIPHER_GCMP:
@@ -1126,29 +1151,11 @@
 }
 
 
-enum wpa_cipher wpa_cipher_to_suite_driver(int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_NONE:
-		return CIPHER_NONE;
-	case WPA_CIPHER_WEP40:
-		return CIPHER_WEP40;
-	case WPA_CIPHER_WEP104:
-		return CIPHER_WEP104;
-	case WPA_CIPHER_CCMP:
-		return CIPHER_CCMP;
-	case WPA_CIPHER_GCMP:
-		return CIPHER_GCMP;
-	case WPA_CIPHER_TKIP:
-	default:
-		return CIPHER_TKIP;
-	}
-}
-
-
 int wpa_cipher_valid_pairwise(int cipher)
 {
-	return cipher == WPA_CIPHER_CCMP ||
+	return cipher == WPA_CIPHER_CCMP_256 ||
+		cipher == WPA_CIPHER_GCMP_256 ||
+		cipher == WPA_CIPHER_CCMP ||
 		cipher == WPA_CIPHER_GCMP ||
 		cipher == WPA_CIPHER_TKIP;
 }
@@ -1156,6 +1163,10 @@
 
 u32 wpa_cipher_to_suite(int proto, int cipher)
 {
+	if (cipher & WPA_CIPHER_CCMP_256)
+		return RSN_CIPHER_SUITE_CCMP_256;
+	if (cipher & WPA_CIPHER_GCMP_256)
+		return RSN_CIPHER_SUITE_GCMP_256;
 	if (cipher & WPA_CIPHER_CCMP)
 		return (proto == WPA_PROTO_RSN ?
 			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
@@ -1173,6 +1184,8 @@
 	if (cipher & WPA_CIPHER_NONE)
 		return (proto == WPA_PROTO_RSN ?
 			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+	if (cipher & WPA_CIPHER_GTK_NOT_USED)
+		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
 	return 0;
 }
 
@@ -1181,6 +1194,16 @@
 {
 	int num_suites = 0;
 
+	if (ciphers & WPA_CIPHER_CCMP_256) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_GCMP_256) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
 	if (ciphers & WPA_CIPHER_CCMP) {
 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
 		pos += RSN_SELECTOR_LEN;
@@ -1232,6 +1255,10 @@
 
 int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
 {
+	if (ciphers & WPA_CIPHER_CCMP_256)
+		return WPA_CIPHER_CCMP_256;
+	if (ciphers & WPA_CIPHER_GCMP_256)
+		return WPA_CIPHER_GCMP_256;
 	if (ciphers & WPA_CIPHER_CCMP)
 		return WPA_CIPHER_CCMP;
 	if (ciphers & WPA_CIPHER_GCMP)
@@ -1246,10 +1273,16 @@
 
 int wpa_pick_group_cipher(int ciphers)
 {
+	if (ciphers & WPA_CIPHER_CCMP_256)
+		return WPA_CIPHER_CCMP_256;
+	if (ciphers & WPA_CIPHER_GCMP_256)
+		return WPA_CIPHER_GCMP_256;
 	if (ciphers & WPA_CIPHER_CCMP)
 		return WPA_CIPHER_CCMP;
 	if (ciphers & WPA_CIPHER_GCMP)
 		return WPA_CIPHER_GCMP;
+	if (ciphers & WPA_CIPHER_GTK_NOT_USED)
+		return WPA_CIPHER_GTK_NOT_USED;
 	if (ciphers & WPA_CIPHER_TKIP)
 		return WPA_CIPHER_TKIP;
 	if (ciphers & WPA_CIPHER_WEP104)
@@ -1280,7 +1313,11 @@
 			end++;
 		last = *end == '\0';
 		*end = '\0';
-		if (os_strcmp(start, "CCMP") == 0)
+		if (os_strcmp(start, "CCMP-256") == 0)
+			val |= WPA_CIPHER_CCMP_256;
+		else if (os_strcmp(start, "GCMP-256") == 0)
+			val |= WPA_CIPHER_GCMP_256;
+		else if (os_strcmp(start, "CCMP") == 0)
 			val |= WPA_CIPHER_CCMP;
 		else if (os_strcmp(start, "GCMP") == 0)
 			val |= WPA_CIPHER_GCMP;
@@ -1292,6 +1329,8 @@
 			val |= WPA_CIPHER_WEP40;
 		else if (os_strcmp(start, "NONE") == 0)
 			val |= WPA_CIPHER_NONE;
+		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
+			val |= WPA_CIPHER_GTK_NOT_USED;
 		else {
 			os_free(buf);
 			return -1;
@@ -1312,6 +1351,20 @@
 	char *pos = start;
 	int ret;
 
+	if (ciphers & WPA_CIPHER_CCMP_256) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
+				  pos == start ? "" : delim);
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (ciphers & WPA_CIPHER_GCMP_256) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
+				  pos == start ? "" : delim);
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
 	if (ciphers & WPA_CIPHER_CCMP) {
 		ret = os_snprintf(pos, end - pos, "%sCCMP",
 				  pos == start ? "" : delim);
@@ -1373,5 +1426,11 @@
 		return WPA_CIPHER_TKIP;
 	if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
 		return WPA_CIPHER_GCMP;
+	if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
+			 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
+		return WPA_CIPHER_GCMP_256;
+	if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
+			 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
+		return WPA_CIPHER_CCMP_256;
 	return WPA_CIPHER_CCMP;
 }
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 2d63662..dcc035c 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -21,10 +21,12 @@
 #define WPA_GTK_MAX_LEN 32
 
 #define WPA_ALLOWED_PAIRWISE_CIPHERS \
-(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
 #define WPA_ALLOWED_GROUP_CIPHERS \
 (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
-WPA_CIPHER_WEP40)
+WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
+WPA_CIPHER_GTK_NOT_USED)
 
 #define WPA_SELECTOR_LEN 4
 #define WPA_VERSION 1
@@ -60,6 +62,10 @@
 #define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
 #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 \
+RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 #define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
 
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
@@ -75,6 +81,11 @@
 #endif /* CONFIG_IEEE80211W */
 #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
 #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_CIPHER_SUITE_CCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 
 /* EAPOL-Key Key Data Encapsulation
  * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -98,6 +109,9 @@
 #define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
 #define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
 
+#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
+#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
+
 #define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
 
 #define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
@@ -392,7 +406,6 @@
 int wpa_cipher_key_len(int cipher);
 int wpa_cipher_rsc_len(int cipher);
 int wpa_cipher_to_alg(int cipher);
-enum wpa_cipher wpa_cipher_to_suite_driver(int cipher);
 int wpa_cipher_valid_pairwise(int cipher);
 u32 wpa_cipher_to_suite(int proto, int cipher);
 int rsn_cipher_put_suites(u8 *pos, int ciphers);
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 83788d7..f4af94a 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -391,7 +391,7 @@
 		     void (*msg_cb)(char *msg, size_t len))
 {
 	struct timeval tv;
-	struct os_time started_at;
+	struct os_reltime started_at;
 	int res;
 	fd_set rfds;
 	const char *_cmd;
@@ -430,12 +430,12 @@
 			 * longer before giving up.
 			 */
 			if (started_at.sec == 0)
-				os_get_time(&started_at);
+				os_get_reltime(&started_at);
 			else {
-				struct os_time n;
-				os_get_time(&n);
+				struct os_reltime n;
+				os_get_reltime(&n);
 				/* Try for a few seconds. */
-				if (n.sec > started_at.sec + 5)
+				if (os_reltime_expired(&n, &started_at, 5))
 					goto send_err;
 			}
 			os_sleep(1, 0);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index fd7f686..759cee4 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -54,6 +54,8 @@
 #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
 /** Temporarily disabled network block re-enabled */
 #define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
+/** New scan started */
+#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
 /** New scan results available */
 #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
 /** wpa_supplicant state change */
@@ -62,14 +64,18 @@
 #define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
 /** A BSS entry was removed (followed by BSS entry id and BSSID) */
 #define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
-#ifdef ANDROID_P2P
-/** Notify the Userspace about the freq conflict */
-#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
-#endif
 
 /** RSN IBSS 4-way handshakes completed with specified peer */
 #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
 
+/** Notification of frequency conflict due to a concurrent operation.
+ *
+ * The indicated network is disabled and needs to be re-enabled before it can
+ * be used again.
+ */
+#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
+/** Frequency ranges that the driver recommends to avoid */
+#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
 /** WPS overlap detected in PBC mode */
 #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
 /** Available WPS AP with active PBC found in scan results */
@@ -143,14 +149,27 @@
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
 #define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
+#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
+#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 "
 
 /* 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 INTERWORKING_AP "INTERWORKING-AP "
 #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
 
 #define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+/* parameters: <addr> <dialog_token> <freq> */
+#define GAS_QUERY_START "GAS-QUERY-START "
+/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
+#define GAS_QUERY_DONE "GAS-QUERY-DONE "
+
+#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
+#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
 
 /* hostapd control interface - fixed message prefixes */
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -166,6 +185,21 @@
 #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
 #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
 
+#define AP_EVENT_ENABLED "AP-ENABLED "
+#define AP_EVENT_DISABLED "AP-DISABLED "
+
+#define ACS_EVENT_STARTED "ACS-STARTED "
+#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
+#define ACS_EVENT_FAILED "ACS-FAILED "
+
+#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
+#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
+#define DFS_EVENT_CAC_START "DFS-CAC-START "
+#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
+#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+
+#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index a605a65..fcf9586 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -1,7 +1,7 @@
 all: libcrypto.a
 
 clean:
-	rm -f *~ *.o *.d libcrypto.a
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcrypto.a
 
 install:
 	@echo Nothing to be made.
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 9bccaaa..4caa277 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -534,16 +534,6 @@
 			  struct crypto_bignum *d);
 
 /**
- * crypto_bignum_rshift - b = a >> n
- * @a: Bignum
- * @n: Number of bits to shift
- * @b: Bignum; used to store the result of a >> n
- * Returns: 0 on success, -1 on failure
- */
-int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
-			 struct crypto_bignum *b);
-
-/**
  * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
  * @a: Bignum
  * @b: Bignum
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 5215c00..817ee2d 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -26,6 +26,8 @@
 #include "common.h"
 #include "wpabuf.h"
 #include "dh_group5.h"
+#include "sha1.h"
+#include "sha256.h"
 #include "crypto.h"
 
 #if OPENSSL_VERSION_NUMBER < 0x00907000
@@ -914,13 +916,6 @@
 }
 
 
-int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
-			 struct crypto_bignum *b)
-{
-	return BN_rshift((BIGNUM *) b, (const BIGNUM *) a, n) ? 0 : -1;
-}
-
-
 int crypto_bignum_inverse(const struct crypto_bignum *a,
 			  const struct crypto_bignum *b,
 			  struct crypto_bignum *c)
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 3a675df..58e94c3 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1169,7 +1169,7 @@
 #endif /* ALL_DH_GROUPS */
 };
 
-#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+#define NUM_DH_GROUPS ARRAY_SIZE(dh_groups)
 
 
 const struct dh_group * dh_groups_get(int id)
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index b2bbab2..49a5c1c 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -58,6 +58,7 @@
 				WPA_PUT_LE16(ucs2_buffer + j,
 					     ((c & 0xF) << 12) |
 					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+				j += 2;
 			}
 		}
 	}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 2fdaa02..88afae4 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -40,7 +40,8 @@
 	TLS_FAIL_SUBJECT_MISMATCH = 5,
 	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 	TLS_FAIL_BAD_CERTIFICATE = 7,
-	TLS_FAIL_SERVER_CHAIN_PROBE = 8
+	TLS_FAIL_SERVER_CHAIN_PROBE = 8,
+	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
 };
 
 union tls_event_data {
@@ -84,6 +85,8 @@
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
 #define TLS_CONN_REQUEST_OCSP BIT(3)
 #define TLS_CONN_REQUIRE_OCSP BIT(4)
+#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
+#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -96,6 +99,8 @@
  * %NULL to allow all subjects
  * @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
  * @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
@@ -137,6 +142,7 @@
 	const char *ca_path;
 	const char *subject_match;
 	const char *altsubject_match;
+	const char *suffix_match;
 	const char *client_cert;
 	const u8 *client_cert_blob;
 	size_t client_cert_blob_len;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index a5d72f4..cb23eb9 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -125,8 +125,6 @@
 }
 
 
-extern int wpa_debug_show_keys;
-
 void * tls_init(const struct tls_config *conf)
 {
 	struct tls_global *global;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index d27af0a..e606828 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -48,23 +48,6 @@
 #endif
 #endif
 
-#ifdef ANDROID
-#include <openssl/pem.h>
-#include <keystore/keystore_get.h>
-
-static BIO * BIO_from_keystore(const char *key)
-{
-    BIO *bio = NULL;
-    uint8_t *value = NULL;
-    int length = keystore_get(key, strlen(key), &value);
-    if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) {
-        BIO_write(bio, value, length);
-    }
-    free(value);
-    return bio;
-}
-#endif /* ANDROID */
-
 #ifdef SSL_set_tlsext_status_type
 #ifndef OPENSSL_NO_TLSEXT
 #define HAVE_OCSP
@@ -72,6 +55,22 @@
 #endif /* OPENSSL_NO_TLSEXT */
 #endif /* SSL_set_tlsext_status_type */
 
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include <keystore/keystore_get.h>
+
+static BIO * BIO_from_keystore(const char *key)
+{
+	BIO *bio = NULL;
+	uint8_t *value = NULL;
+	int length = keystore_get(key, strlen(key), &value);
+	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+		BIO_write(bio, value, length);
+	free(value);
+	return bio;
+}
+#endif /* ANDROID */
+
 static int tls_openssl_ref_count = 0;
 
 struct tls_context {
@@ -93,7 +92,7 @@
 	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;
+	char *subject_match, *altsubject_match, *suffix_match;
 	int read_alerts, write_alerts, failed;
 
 	tls_session_ticket_cb session_ticket_cb;
@@ -113,6 +112,7 @@
 
 	X509 *peer_cert;
 	X509 *peer_issuer;
+	X509 *peer_issuer_issuer;
 };
 
 
@@ -798,11 +798,13 @@
 	ssl = SSL_CTX_new(TLSv1_method());
 	if (ssl == NULL) {
 		tls_openssl_ref_count--;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+		if (context != tls_global)
+			os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 		if (tls_openssl_ref_count == 0) {
 			os_free(tls_global);
 			tls_global = NULL;
-		} else if (context != tls_global) {
-			os_free(context);
 		}
 		return NULL;
 	}
@@ -1009,11 +1011,6 @@
 #ifdef SSL_OP_NO_COMPRESSION
 	options |= SSL_OP_NO_COMPRESSION;
 #endif /* SSL_OP_NO_COMPRESSION */
-#ifdef ANDROID
-	options |= SSL_OP_NO_TLSv1_1;
-	options |= SSL_OP_NO_TLSv1_2;
-	options |= SSL_OP_NO_TICKET;
-#endif /* ANDROID */
 	SSL_set_options(conn->ssl, options);
 
 	conn->ssl_in = BIO_new(BIO_s_mem());
@@ -1049,6 +1046,7 @@
 	tls_engine_deinit(conn);
 	os_free(conn->subject_match);
 	os_free(conn->altsubject_match);
+	os_free(conn->suffix_match);
 	os_free(conn->session_ticket);
 	os_free(conn);
 }
@@ -1139,6 +1137,104 @@
 }
 
 
+#ifndef CONFIG_NATIVE_WINDOWS
+static int domain_suffix_match(const u8 *val, size_t len, const char *match)
+{
+	size_t i, match_len;
+
+	/* Check for embedded nuls that could mess up suffix matching */
+	for (i = 0; i < len; i++) {
+		if (val[i] == '\0') {
+			wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
+			return 0;
+		}
+	}
+
+	match_len = os_strlen(match);
+	if (match_len > len)
+		return 0;
+
+	if (os_strncasecmp((const char *) val + len - match_len, match,
+			   match_len) != 0)
+		return 0; /* no match */
+
+	if (match_len == len)
+		return 1; /* exact match */
+
+	if (val[len - match_len - 1] == '.')
+		return 1; /* full label match completes suffix match */
+
+	wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+	return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	/* wincrypt.h has conflicting X509_NAME definition */
+	return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+	GENERAL_NAME *gen;
+	void *ext;
+	int i;
+	int dns_name = 0;
+	X509_NAME *name;
+
+	wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+
+	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);
+		if (gen->type != GEN_DNS)
+			continue;
+		dns_name++;
+		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+				  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");
+			return 1;
+		}
+	}
+
+	if (dns_name) {
+		wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+		return 0;
+	}
+
+	name = X509_get_subject_name(cert);
+	i = -1;
+	for (;;) {
+		X509_NAME_ENTRY *e;
+		ASN1_STRING *cn;
+
+		i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
+		if (i == -1)
+			break;
+		e = X509_NAME_get_entry(name, i);
+		if (e == NULL)
+			continue;
+		cn = X509_NAME_ENTRY_get_data(e);
+		if (cn == NULL)
+			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");
+			return 1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+	return 0;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
 static enum tls_fail_reason openssl_tls_fail_reason(int err)
 {
 	switch (err) {
@@ -1267,10 +1363,13 @@
 	SSL *ssl;
 	struct tls_connection *conn;
 	struct tls_context *context;
-	char *match, *altmatch;
+	char *match, *altmatch, *suffix_match;
 	const char *err_str;
 
 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	if (!err_cert)
+		return 0;
+
 	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,
@@ -1285,10 +1384,13 @@
 		conn->peer_cert = err_cert;
 	else if (depth == 1)
 		conn->peer_issuer = err_cert;
+	else if (depth == 2)
+		conn->peer_issuer_issuer = err_cert;
 
 	context = conn->context;
 	match = conn->subject_match;
 	altmatch = conn->altsubject_match;
+	suffix_match = conn->suffix_match;
 
 	if (!preverify_ok && !conn->ca_cert_verify)
 		preverify_ok = 1;
@@ -1357,6 +1459,14 @@
 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 				       "AltSubject mismatch",
 				       TLS_FAIL_ALTSUBJECT_MISMATCH);
+	} else if (depth == 0 && suffix_match &&
+		   !tls_match_suffix(err_cert, suffix_match)) {
+		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
 		openssl_tls_cert_event(conn, err_cert, depth, buf);
 
@@ -1619,7 +1729,8 @@
 
 static int tls_connection_set_subject_match(struct tls_connection *conn,
 					    const char *subject_match,
-					    const char *altsubject_match)
+					    const char *altsubject_match,
+					    const char *suffix_match)
 {
 	os_free(conn->subject_match);
 	conn->subject_match = NULL;
@@ -1637,6 +1748,14 @@
 			return -1;
 	}
 
+	os_free(conn->suffix_match);
+	conn->suffix_match = NULL;
+	if (suffix_match) {
+		conn->suffix_match = os_strdup(suffix_match);
+		if (conn->suffix_match == NULL)
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -2772,7 +2891,6 @@
 static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
 {
 #ifndef CONFIG_NO_STDOUT_DEBUG
-	extern int wpa_debug_level;
 	BIO *out;
 	size_t rlen;
 	char *txt;
@@ -2813,6 +2931,8 @@
 	OCSP_BASICRESP *basic;
 	OCSP_CERTID *id;
 	ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+	X509_STORE *store;
+	STACK_OF(X509) *certs = NULL;
 
 	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
 	if (!p) {
@@ -2843,8 +2963,41 @@
 		return 0;
 	}
 
-	status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx),
-				   0);
+	store = SSL_CTX_get_cert_store(s->ctx);
+	if (conn->peer_issuer) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
+		X509_print_fp(stdout, conn->peer_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");
+		}
+		certs = sk_X509_new_null();
+		if (certs) {
+			X509 *cert;
+			cert = X509_dup(conn->peer_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");
+				X509_free(cert);
+				sk_X509_free(certs);
+				certs = NULL;
+			}
+			if (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");
+					X509_free(cert);
+				}
+			}
+		}
+	}
+
+	status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
+	sk_X509_pop_free(certs, X509_free);
 	if (status <= 0) {
 		tls_show_errors(MSG_INFO, __func__,
 				"OpenSSL: OCSP response failed verification");
@@ -2855,8 +3008,15 @@
 
 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
 
-	if (!conn->peer_cert || !conn->peer_issuer) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate or issue certificate not available for OCSP status check");
+	if (!conn->peer_cert) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	if (!conn->peer_issuer) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
 		OCSP_BASICRESP_free(basic);
 		OCSP_RESPONSE_free(rsp);
 		return 0;
@@ -2902,7 +3062,7 @@
 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
 		return 0;
 	}
-		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
 	return 1;
 }
 
@@ -2947,7 +3107,6 @@
 {
 	int ret;
 	unsigned long err;
-	SSL_CTX *ssl_ctx = tls_ctx;
 
 	if (conn == NULL)
 		return -1;
@@ -2967,7 +3126,8 @@
 	}
 	if (tls_connection_set_subject_match(conn,
 					     params->subject_match,
-					     params->altsubject_match))
+					     params->altsubject_match,
+					     params->suffix_match))
 		return -1;
 
 	if (params->engine && params->ca_cert_id) {
@@ -3017,8 +3177,22 @@
 #endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef SSL_OP_NO_TLSv1_1
+	if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
+		SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
+	else
+		SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+	if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
+		SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
+	else
+		SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+
 #ifdef HAVE_OCSP
 	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		SSL_CTX *ssl_ctx = tls_ctx;
 		SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
 		SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
 		SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
diff --git a/src/drivers/Makefile b/src/drivers/Makefile
index 07600e5..5721154 100644
--- a/src/drivers/Makefile
+++ b/src/drivers/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 	rm -f build.wpa_supplicant build.hostapd
 
 install:
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
index 5906527..31d9440 100644
--- a/src/drivers/android_drv.h
+++ b/src/drivers/android_drv.h
@@ -1,12 +1,8 @@
 /*
  * Android driver interface
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef ANDROID_DRV_H
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8c9829..632ae3a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
 /*
  * Driver interface definition
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -37,6 +37,19 @@
 #define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
 #define HOSTAPD_CHAN_DFS_MASK 0x00000300
 
+#define HOSTAPD_CHAN_VHT_10_70 0x00000800
+#define HOSTAPD_CHAN_VHT_30_50 0x00001000
+#define HOSTAPD_CHAN_VHT_50_30 0x00002000
+#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+
+enum reg_change_initiator {
+	REGDOM_SET_BY_CORE,
+	REGDOM_SET_BY_USER,
+	REGDOM_SET_BY_DRIVER,
+	REGDOM_SET_BY_COUNTRY_IE,
+	REGDOM_BEACON_HINT,
+};
+
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -57,7 +70,7 @@
 	int flag;
 
 	/**
-	 * max_tx_power - Maximum transmit power in dBm
+	 * max_tx_power - Regulatory transmit power limit in dBm
 	 */
 	u8 max_tx_power;
 
@@ -221,7 +234,7 @@
 struct wpa_scan_results {
 	struct wpa_scan_res **res;
 	size_t num;
-	struct os_time fetch_time;
+	struct os_reltime fetch_time;
 };
 
 /**
@@ -328,6 +341,21 @@
 	 * and not to transmit the frames at any of those rates.
 	 */
 	u8 p2p_probe;
+
+	/**
+	 * only_new_results - Request driver to report only new results
+	 *
+	 * This is used to request the driver to report only BSSes that have
+	 * been detected after this scan request has been started, i.e., to
+	 * flush old cached BSS entries.
+	 */
+	int only_new_results;
+
+	/*
+	 * NOTE: Whenever adding new parameters here, please make sure
+	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
+	 * matching changes.
+	 */
 };
 
 /**
@@ -376,6 +404,16 @@
 	const u8 *bssid;
 
 	/**
+	 * bssid_hint - BSSID of a proposed AP
+	 *
+	 * This indicates which BSS has been found a suitable candidate for
+	 * initial association for drivers that use driver/firmwate-based BSS
+	 * selection. Unlike the @bssid parameter, @bssid_hint does not limit
+	 * the driver from selecting other BSSes in the ESS.
+	 */
+	const u8 *bssid_hint;
+
+	/**
 	 * ssid - The selected SSID
 	 */
 	const u8 *ssid;
@@ -393,6 +431,16 @@
 	int freq;
 
 	/**
+	 * freq_hint - Frequency of the channel the proposed AP is using
+	 *
+	 * This provides a channel on which a suitable BSS has been found as a
+	 * hint for the driver. Unlike the @freq parameter, @freq_hint does not
+	 * limit the driver from selecting other channels for
+	 * driver/firmware-based BSS selection.
+	 */
+	int freq_hint;
+
+	/**
 	 * bg_scan_period - Background scan period in seconds, 0 to disable
 	 * background scan, or -1 to indicate no change to default driver
 	 * configuration
@@ -430,25 +478,25 @@
 	unsigned int wpa_proto;
 
 	/**
-	 * pairwise_suite - Selected pairwise cipher suite
+	 * pairwise_suite - Selected pairwise cipher suite (WPA_CIPHER_*)
 	 *
 	 * This is usually ignored if @wpa_ie is used.
 	 */
-	enum wpa_cipher pairwise_suite;
+	unsigned int pairwise_suite;
 
 	/**
-	 * group_suite - Selected group cipher suite
+	 * group_suite - Selected group cipher suite (WPA_CIPHER_*)
 	 *
 	 * This is usually ignored if @wpa_ie is used.
 	 */
-	enum wpa_cipher group_suite;
+	unsigned int group_suite;
 
 	/**
-	 * key_mgmt_suite - Selected key management suite
+	 * key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*)
 	 *
 	 * This is usually ignored if @wpa_ie is used.
 	 */
-	enum wpa_key_mgmt key_mgmt_suite;
+	unsigned int key_mgmt_suite;
 
 	/**
 	 * auth_alg - Allowed authentication algorithms
@@ -622,7 +670,7 @@
 	/**
 	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
 	 */
-	const u8 *head;
+	u8 *head;
 
 	/**
 	 * head_len - Length of the head buffer in octets
@@ -632,7 +680,7 @@
 	/**
 	 * tail - Beacon tail following TIM IE
 	 */
-	const u8 *tail;
+	u8 *tail;
 
 	/**
 	 * tail_len - Length of the tail buffer in octets
@@ -663,7 +711,7 @@
 	 * This is used by drivers that reply to Probe Requests internally in
 	 * AP mode and require the full Probe Response template.
 	 */
-	const u8 *proberesp;
+	u8 *proberesp;
 
 	/**
 	 * proberesp_len - Length of the proberesp buffer in octets
@@ -821,6 +869,12 @@
 #define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
 #define WPA_DRIVER_CAPA_ENC_WEP128	0x00000010
 #define WPA_DRIVER_CAPA_ENC_GCMP	0x00000020
+#define WPA_DRIVER_CAPA_ENC_GCMP_256	0x00000040
+#define WPA_DRIVER_CAPA_ENC_CCMP_256	0x00000080
+#define WPA_DRIVER_CAPA_ENC_BIP		0x00000100
+#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_128	0x00000200
+#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256	0x00000400
+#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256	0x00000800
 	unsigned int enc;
 
 #define WPA_DRIVER_AUTH_OPEN		0x00000001
@@ -844,8 +898,7 @@
 #define WPA_DRIVER_FLAGS_AP		0x00000040
 /* Driver needs static WEP key setup after association has been completed */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
-/* Driver takes care of P2P management operations */
-#define WPA_DRIVER_FLAGS_P2P_MGMT	0x00000100
+/* unused: 0x00000100 */
 /* Driver supports concurrent P2P operations */
 #define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
 /*
@@ -898,6 +951,10 @@
 #define WPA_DRIVER_FLAGS_RADAR				0x10000000
 /* Driver supports a dedicated interface for P2P Device */
 #define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
+/* Driver supports QoS Mapping */
+#define WPA_DRIVER_FLAGS_QOS_MAPPING			0x40000000
+/* Driver supports CSA in AP mode */
+#define WPA_DRIVER_FLAGS_AP_CSA				0x80000000
 	unsigned int flags;
 
 	int max_scan_ssids;
@@ -971,11 +1028,17 @@
 	u16 listen_interval;
 	const struct ieee80211_ht_capabilities *ht_capabilities;
 	const struct ieee80211_vht_capabilities *vht_capabilities;
+	int vht_opmode_enabled;
+	u8 vht_opmode;
 	u32 flags; /* bitmask of WPA_STA_* flags */
 	int set; /* Set STA parameters instead of add */
 	u8 qosinfo;
 	const u8 *ext_capab;
 	size_t ext_capab_len;
+	const u8 *supp_channels;
+	size_t supp_channels_len;
+	const u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
 };
 
 struct hostapd_freq_params {
@@ -1087,17 +1150,6 @@
 #define WPA_STA_MFP BIT(3)
 #define WPA_STA_TDLS_PEER BIT(4)
 
-/**
- * struct p2p_params - P2P parameters for driver-based P2P management
- */
-struct p2p_params {
-	const char *dev_name;
-	u8 pri_dev_type[8];
-#define DRV_MAX_SEC_DEV_TYPES 5
-	u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
-	size_t num_sec_dev_types;
-};
-
 enum tdls_oper {
 	TDLS_DISCOVERY_REQ,
 	TDLS_SETUP,
@@ -1152,6 +1204,59 @@
 };
 
 /**
+ * struct beacon_data - Beacon data
+ * @head: Head portion of Beacon frame (before TIM IE)
+ * @tail: Tail portion of Beacon frame (after TIM IE)
+ * @beacon_ies: Extra information element(s) to add into Beacon frames or %NULL
+ * @proberesp_ies: Extra information element(s) to add into Probe Response
+ *	frames or %NULL
+ * @assocresp_ies: Extra information element(s) to add into (Re)Association
+ *	Response frames or %NULL
+ * @probe_resp: Probe Response frame template
+ * @head_len: Length of @head
+ * @tail_len: Length of @tail
+ * @beacon_ies_len: Length of beacon_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @probe_resp_len: Length of probe response template (@probe_resp)
+ */
+struct beacon_data {
+	u8 *head, *tail;
+	u8 *beacon_ies;
+	u8 *proberesp_ies;
+	u8 *assocresp_ies;
+	u8 *probe_resp;
+
+	size_t head_len, tail_len;
+	size_t beacon_ies_len;
+	size_t proberesp_ies_len;
+	size_t assocresp_ies_len;
+	size_t probe_resp_len;
+};
+
+/**
+ * struct csa_settings - Settings for channel switch command
+ * @cs_count: Count in Beacon frames (TBTT) to perform the switch
+ * @block_tx: 1 - block transmission for CSA period
+ * @freq_params: Next channel frequency parameter
+ * @beacon_csa: Beacon/probe resp/asooc resp info for CSA period
+ * @beacon_after: Next beacon/probe resp/asooc resp info
+ * @counter_offset_beacon: Offset to the count field in beacon's tail
+ * @counter_offset_presp: Offset to the count field in probe resp.
+ */
+struct csa_settings {
+	u8 cs_count;
+	u8 block_tx;
+
+	struct hostapd_freq_params freq_params;
+	struct beacon_data beacon_csa;
+	struct beacon_data beacon_after;
+
+	u16 counter_offset_beacon;
+	u16 counter_offset_presp;
+};
+
+/**
  * struct wpa_driver_ops - Driver interface API definition
  *
  * This structure defines the API that each driver interface needs to implement
@@ -1200,7 +1305,9 @@
 	 * @priv: private driver interface data
 	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
 	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
-	 *	%WPA_ALG_GCMP);
+	 *	%WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
+	 *	%WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
+	 *	%WPA_ALG_BIP_CMAC_256);
 	 *	%WPA_ALG_NONE clears the key.
 	 * @addr: Address of the peer STA (BSSID of the current AP when setting
 	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
@@ -1565,6 +1672,14 @@
 	int (*set_country)(void *priv, const char *alpha2);
 
 	/**
+	 * get_country - Get country
+	 * @priv: Private driver interface data
+	 * @alpha2: Buffer for returning country code (at least 3 octets)
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*get_country)(void *priv, char *alpha2);
+
+	/**
 	 * global_init - Global driver initialization
 	 * Returns: Pointer to private data (global), %NULL on failure
 	 *
@@ -1950,12 +2065,13 @@
 	 *	(this may differ from the requested addr if the driver cannot
 	 *	change interface address)
 	 * @bridge: Bridge interface to use or %NULL if no bridge configured
+	 * @use_existing: Whether to allow existing interface to be used
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*if_add)(void *priv, enum wpa_driver_if_type type,
 		      const char *ifname, const u8 *addr, void *bss_ctx,
 		      void **drv_priv, char *force_ifname, u8 *if_addr,
-		      const char *bridge);
+		      const char *bridge, int use_existing);
 
 	/**
 	 * if_remove - Remove a virtual interface
@@ -2132,7 +2248,7 @@
 	 *
 	 * This command is used to request the driver to remain awake on the
 	 * specified channel for the specified duration and report received
-	 * Action frames with EVENT_RX_ACTION events. Optionally, received
+	 * Action frames with EVENT_RX_MGMT events. Optionally, received
 	 * Probe Request frames may also be requested to be reported by calling
 	 * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
 	 *
@@ -2314,222 +2430,6 @@
 	const char * (*get_radio_name)(void *priv);
 
 	/**
-	 * p2p_find - Start P2P Device Discovery
-	 * @priv: Private driver interface data
-	 * @timeout: Timeout for find operation in seconds or 0 for no timeout
-	 * @type: Device Discovery type (enum p2p_discovery_type)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_find)(void *priv, unsigned int timeout, int type);
-
-	/**
-	 * p2p_stop_find - Stop P2P Device Discovery
-	 * @priv: Private driver interface data
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_stop_find)(void *priv);
-
-	/**
-	 * p2p_listen - Start P2P Listen state for specified duration
-	 * @priv: Private driver interface data
-	 * @timeout: Listen state duration in milliseconds
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function can be used to request the P2P module to keep the
-	 * device discoverable on the listen channel for an extended set of
-	 * time. At least in its current form, this is mainly used for testing
-	 * purposes and may not be of much use for normal P2P operations.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_listen)(void *priv, unsigned int timeout);
-
-	/**
-	 * p2p_connect - Start P2P group formation (GO negotiation)
-	 * @priv: Private driver interface data
-	 * @peer_addr: MAC address of the peer P2P client
-	 * @wps_method: enum p2p_wps_method value indicating config method
-	 * @go_intent: Local GO intent value (1..15)
-	 * @own_interface_addr: Intended interface address to use with the
-	 *	group
-	 * @force_freq: The only allowed channel frequency in MHz or 0
-	 * @persistent_group: Whether to create persistent group
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method,
-			   int go_intent, const u8 *own_interface_addr,
-			   unsigned int force_freq, int persistent_group);
-
-	/**
-	 * wps_success_cb - Report successfully completed WPS provisioning
-	 * @priv: Private driver interface data
-	 * @peer_addr: Peer address
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is used to report successfully completed WPS
-	 * provisioning during group formation in both GO/Registrar and
-	 * client/Enrollee roles.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*wps_success_cb)(void *priv, const u8 *peer_addr);
-
-	/**
-	 * p2p_group_formation_failed - Report failed WPS provisioning
-	 * @priv: Private driver interface data
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is used to report failed group formation. This can
-	 * happen either due to failed WPS provisioning or due to 15 second
-	 * timeout during the provisioning phase.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_group_formation_failed)(void *priv);
-
-	/**
-	 * p2p_set_params - Set P2P parameters
-	 * @priv: Private driver interface data
-	 * @params: P2P parameters
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_set_params)(void *priv, const struct p2p_params *params);
-
-	/**
-	 * p2p_prov_disc_req - Send Provision Discovery Request
-	 * @priv: Private driver interface data
-	 * @peer_addr: MAC address of the peer P2P client
-	 * @config_methods: WPS Config Methods value (only one bit set)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function can be used to request a discovered P2P peer to
-	 * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared
-	 * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The
-	 * Provision Discovery Request frame is transmitted once immediately
-	 * and if no response is received, the frame will be sent again
-	 * whenever the target device is discovered during device dsicovery
-	 * (start with a p2p_find() call). Response from the peer is indicated
-	 * with the EVENT_P2P_PROV_DISC_RESPONSE event.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
-				 u16 config_methods, int join);
-
-	/**
-	 * p2p_sd_request - Schedule a service discovery query
-	 * @priv: Private driver interface data
-	 * @dst: Destination peer or %NULL to apply for all peers
-	 * @tlvs: P2P Service Query TLV(s)
-	 * Returns: Reference to the query or 0 on failure
-	 *
-	 * Response to the query is indicated with the
-	 * EVENT_P2P_SD_RESPONSE driver event.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	u64 (*p2p_sd_request)(void *priv, const u8 *dst,
-			      const struct wpabuf *tlvs);
-
-	/**
-	 * p2p_sd_cancel_request - Cancel a pending service discovery query
-	 * @priv: Private driver interface data
-	 * @req: Query reference from p2p_sd_request()
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_sd_cancel_request)(void *priv, u64 req);
-
-	/**
-	 * p2p_sd_response - Send response to a service discovery query
-	 * @priv: Private driver interface data
-	 * @freq: Frequency from EVENT_P2P_SD_REQUEST event
-	 * @dst: Destination address from EVENT_P2P_SD_REQUEST event
-	 * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event
-	 * @resp_tlvs: P2P Service Response TLV(s)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is called as a response to the request indicated with
-	 * the EVENT_P2P_SD_REQUEST driver event.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_sd_response)(void *priv, int freq, const u8 *dst,
-			       u8 dialog_token,
-			       const struct wpabuf *resp_tlvs);
-
-	/**
-	 * p2p_service_update - Indicate a change in local services
-	 * @priv: Private driver interface data
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function needs to be called whenever there is a change in
-	 * availability of the local services. This will increment the
-	 * Service Update Indicator value which will be used in SD Request and
-	 * Response frames.
-	 *
-	 * This function is only used if the driver implements P2P management,
-	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
-	 * struct wpa_driver_capa.
-	 */
-	int (*p2p_service_update)(void *priv);
-
-	/**
-	 * p2p_reject - Reject peer device (explicitly block connections)
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the peer
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*p2p_reject)(void *priv, const u8 *addr);
-
-	/**
-	 * p2p_invite - Invite a P2P Device into a group
-	 * @priv: Private driver interface data
-	 * @peer: Device Address of the peer P2P Device
-	 * @role: Local role in the group
-	 * @bssid: Group BSSID or %NULL if not known
-	 * @ssid: Group SSID
-	 * @ssid_len: Length of ssid in octets
-	 * @go_dev_addr: Forced GO Device Address or %NULL if none
-	 * @persistent_group: Whether this is to reinvoke a persistent group
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*p2p_invite)(void *priv, const u8 *peer, int role,
-			  const u8 *bssid, const u8 *ssid, size_t ssid_len,
-			  const u8 *go_dev_addr, int persistent_group);
-
-	/**
 	 * send_tdls_mgmt - for sending TDLS management packets
 	 * @priv: private driver interface data
 	 * @dst: Destination (peer) MAC address
@@ -2572,6 +2472,15 @@
 			u8 *buf, u16 *buf_len);
 
 	/**
+	 * set_qos_map - Set QoS Map
+	 * @priv: Private driver interface data
+	 * @qos_map_set: QoS Map
+	 * @qos_map_set_len: Length of QoS Map
+	 */
+	int (*set_qos_map)(void *priv, const u8 *qos_map_set,
+			   u8 qos_map_set_len);
+
+	/**
 	 * signal_poll - Get current connection information
 	 * @priv: Private driver interface data
 	 * @signal_info: Connection info structure
@@ -2591,18 +2500,19 @@
 	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_authmode)(void *priv, int authmode);
+
 #ifdef ANDROID
 	/**
-	 * driver_cmd - execute driver-specific command
-	 * @priv: private driver interface data
-	 * @cmd: command to execute
-	 * @buf: return buffer
-	 * @buf_len: buffer length
-	 *
+	 * driver_cmd - Execute driver-specific command
+	 * @priv: Private driver interface data
+	 * @cmd: Command to execute
+	 * @buf: Return buffer
+	 * @buf_len: Buffer length
 	 * Returns: 0 on success, -1 on failure
 	 */
-	 int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
-#endif
+	int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif /* ANDROID */
+
 	/**
 	 * set_rekey_info - Set rekey information
 	 * @priv: Private driver interface data
@@ -2735,21 +2645,21 @@
 	 * switch_channel - Announce channel switch and migrate the GO to the
 	 * given frequency
 	 * @priv: Private driver interface data
-	 * @freq: Frequency in MHz
+	 * @settings: Settings for CSA period and new channel
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This function is used to move the GO to the legacy STA channel to
 	 * avoid frequency conflict in single channel concurrency.
 	 */
-	int (*switch_channel)(void *priv, unsigned int freq);
+	int (*switch_channel)(void *priv, struct csa_settings *settings);
 
 	/**
 	 * start_dfs_cac - Listen for radar interference on the channel
 	 * @priv: Private driver interface data
-	 * @freq: Frequency (in MHz) of the channel
+	 * @freq: Channel parameters
 	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*start_dfs_cac)(void *priv, int freq);
+	int (*start_dfs_cac)(void *priv, struct hostapd_freq_params *freq);
 
 	/**
 	 * stop_ap - Removes beacon from AP
@@ -2786,6 +2696,15 @@
 	 * survey.
 	 */
 	int (*get_survey)(void *priv, unsigned int freq);
+
+	/**
+	 * status - Get driver interface status information
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for printing tou the status information
+	 * @buflen: Maximum length of the buffer
+	 * Returns: Length of written status information or -1 on failure
+	 */
+	int (*status)(void *priv, char *buf, size_t buflen);
 };
 
 
@@ -2999,15 +2918,6 @@
 	EVENT_RX_MGMT,
 
 	/**
-	 * EVENT_RX_ACTION - Action frame received
-	 *
-	 * This event is used to indicate when an Action frame has been
-	 * received. Information about the received frame is included in
-	 * union wpa_event_data::rx_action.
-	 */
-	EVENT_RX_ACTION,
-
-	/**
 	 * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
 	 *
 	 * This event is used to indicate when the driver has started the
@@ -3154,38 +3064,6 @@
 	EVENT_STATION_LOW_ACK,
 
 	/**
-	 * EVENT_P2P_DEV_FOUND - Report a discovered P2P device
-	 *
-	 * This event is used only if the driver implements P2P management
-	 * internally. Event data is stored in
-	 * union wpa_event_data::p2p_dev_found.
-	 */
-	EVENT_P2P_DEV_FOUND,
-
-	/**
-	 * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request
-	 *
-	 * This event is used only if the driver implements P2P management
-	 * internally. Event data is stored in
-	 * union wpa_event_data::p2p_go_neg_req_rx.
-	 */
-	EVENT_P2P_GO_NEG_REQ_RX,
-
-	/**
-	 * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation
-	 *
-	 * This event is used only if the driver implements P2P management
-	 * internally. Event data is stored in
-	 * union wpa_event_data::p2p_go_neg_completed.
-	 */
-	EVENT_P2P_GO_NEG_COMPLETED,
-
-	EVENT_P2P_PROV_DISC_REQUEST,
-	EVENT_P2P_PROV_DISC_RESPONSE,
-	EVENT_P2P_SD_REQUEST,
-	EVENT_P2P_SD_RESPONSE,
-
-	/**
 	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
 	 */
 	EVENT_IBSS_PEER_LOST,
@@ -3272,17 +3150,36 @@
 	 */
 	EVENT_DFS_NOP_FINISHED,
 
-	/*
-	* EVENT_SURVEY - Received survey data
-	*
-	* This event gets triggered when a driver query is issued for survey
-	* data and the requested data becomes available. The returned data is
-	* stored in struct survey_results. The results provide at most one
-	* survey entry for each frequency and at minimum will provide one survey
-	* entry for one frequency. The survey data can be os_malloc()'d and
-	* then os_free()'d, so the event callback must only copy data.
-	*/
-	EVENT_SURVEY
+	/**
+	 * EVENT_SURVEY - Received survey data
+	 *
+	 * This event gets triggered when a driver query is issued for survey
+	 * data and the requested data becomes available. The returned data is
+	 * stored in struct survey_results. The results provide at most one
+	 * survey entry for each frequency and at minimum will provide one
+	 * survey entry for one frequency. The survey data can be os_malloc()'d
+	 * and then os_free()'d, so the event callback must only copy data.
+	 */
+	EVENT_SURVEY,
+
+	/**
+	 * EVENT_SCAN_STARTED - Scan started
+	 *
+	 * This indicates that driver has started a scan operation either based
+	 * on a request from wpa_supplicant/hostapd or from another application.
+	 * EVENT_SCAN_RESULTS is used to indicate when the scan has been
+	 * completed (either successfully or by getting cancelled).
+	 */
+	EVENT_SCAN_STARTED,
+
+	/**
+	 * EVENT_AVOID_FREQUENCIES - Received avoid frequency range
+	 *
+	 * This event indicates a set of frequency ranges that should be avoided
+	 * to reduce issues due to interference or internal co-existence
+	 * information in the driver.
+	 */
+	EVENT_AVOID_FREQUENCIES
 };
 
 
@@ -3650,48 +3547,17 @@
 		const u8 *frame;
 		size_t frame_len;
 		u32 datarate;
-		int ssi_signal; /* dBm */
-	} rx_mgmt;
-
-	/**
-	 * struct rx_action - Data for EVENT_RX_ACTION events
-	 */
-	struct rx_action {
-		/**
-		 * da - Destination address of the received Action frame
-		 */
-		const u8 *da;
-
-		/**
-		 * sa - Source address of the received Action frame
-		 */
-		const u8 *sa;
-
-		/**
-		 * bssid - Address 3 of the received Action frame
-		 */
-		const u8 *bssid;
-
-		/**
-		 * category - Action frame category
-		 */
-		u8 category;
-
-		/**
-		 * data - Action frame body after category field
-		 */
-		const u8 *data;
-
-		/**
-		 * len - Length of data in octets
-		 */
-		size_t len;
 
 		/**
 		 * freq - Frequency (in MHz) on which the frame was received
 		 */
 		int freq;
-	} rx_action;
+
+		/**
+		 * ssi_signal - Signal strength in dBm (or 0 if not available)
+		 */
+		int ssi_signal;
+	} rx_mgmt;
 
 	/**
 	 * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
@@ -3831,66 +3697,6 @@
 	} low_ack;
 
 	/**
-	 * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND
-	 */
-	struct p2p_dev_found {
-		const u8 *addr;
-		const u8 *dev_addr;
-		const u8 *pri_dev_type;
-		const char *dev_name;
-		u16 config_methods;
-		u8 dev_capab;
-		u8 group_capab;
-	} p2p_dev_found;
-
-	/**
-	 * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX
-	 */
-	struct p2p_go_neg_req_rx {
-		const u8 *src;
-		u16 dev_passwd_id;
-	} p2p_go_neg_req_rx;
-
-	/**
-	 * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED
-	 */
-	struct p2p_go_neg_completed {
-		struct p2p_go_neg_results *res;
-	} p2p_go_neg_completed;
-
-	struct p2p_prov_disc_req {
-		const u8 *peer;
-		u16 config_methods;
-		const u8 *dev_addr;
-		const u8 *pri_dev_type;
-		const char *dev_name;
-		u16 supp_config_methods;
-		u8 dev_capab;
-		u8 group_capab;
-	} p2p_prov_disc_req;
-
-	struct p2p_prov_disc_resp {
-		const u8 *peer;
-		u16 config_methods;
-	} p2p_prov_disc_resp;
-
-	struct p2p_sd_req {
-		int freq;
-		const u8 *sa;
-		u8 dialog_token;
-		u16 update_indic;
-		const u8 *tlvs;
-		size_t tlvs_len;
-	} p2p_sd_req;
-
-	struct p2p_sd_resp {
-		const u8 *sa;
-		u16 update_indic;
-		const u8 *tlvs;
-		size_t tlvs_len;
-	} p2p_sd_resp;
-
-	/**
 	 * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST
 	 */
 	struct ibss_peer_lost {
@@ -3935,11 +3741,17 @@
 	 * @freq: Frequency of new channel in MHz
 	 * @ht_enabled: Whether this is an HT channel
 	 * @ch_offset: Secondary channel offset
+	 * @ch_width: Channel width
+	 * @cf1: Center frequency 1
+	 * @cf2: Center frequency 2
 	 */
 	struct ch_switch {
 		int freq;
 		int ht_enabled;
 		int ch_offset;
+		enum chan_width ch_width;
+		int cf1;
+		int cf2;
 	} ch_switch;
 
 	/**
@@ -3961,6 +3773,11 @@
 	 */
 	struct dfs_event {
 		int freq;
+		int ht_enabled;
+		int chan_offset;
+		enum chan_width chan_width;
+		int cf1;
+		int cf2;
 	} dfs_event;
 
 	/**
@@ -3973,6 +3790,21 @@
 		unsigned int freq_filter;
 		struct dl_list survey_list; /* struct freq_survey */
 	} survey_results;
+
+	/**
+	 * channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
+	 * @initiator: Initiator of the regulatory change
+	 */
+	struct channel_list_changed {
+		enum reg_change_initiator initiator;
+	} channel_list_changed;
+
+	/**
+	 * freq_range - List of frequency ranges
+	 *
+	 * This is used as the data with EVENT_AVOID_FREQUENCIES.
+	 */
+	struct wpa_freq_range_list freq_range;
 };
 
 /**
@@ -4031,4 +3863,7 @@
 /* Convert wpa_event_type to a string for logging */
 const char * event_to_string(enum wpa_event_type event);
 
+/* NULL terminated array of linked in driver wrappers */
+extern struct wpa_driver_ops *wpa_drivers[];
+
 #endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index c2f5934..23a4e2b 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -354,19 +354,16 @@
 		return atheros_set_privacy(drv, 0);
 	}
 	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
 		return -1;
 	}
 	if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		wpa_printf(MSG_WARNING, "Error configuring WPA state!");
 		return -1;
 	}
 	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
 		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
 		return -1;
 	}
 
@@ -809,16 +806,10 @@
 		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
 		break;
 	case WLAN_FC_STYPE_ACTION:
-		if (&mgmt->u.action.category > buf + len)
-			break;
 		os_memset(&event, 0, sizeof(event));
-		event.rx_action.da = mgmt->da;
-		event.rx_action.sa = mgmt->sa;
-		event.rx_action.bssid = mgmt->bssid;
-		event.rx_action.category = mgmt->u.action.category;
-		event.rx_action.data = &mgmt->u.action.category;
-		event.rx_action.len = buf + len - event.rx_action.data;
-		wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = len;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
 		break;
 	case WLAN_FC_STYPE_AUTH:
 		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
@@ -872,8 +863,59 @@
 	event.rx_mgmt.frame_len = len;
 	wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
 }
+
 #endif /* CONFIG_HS20 */
 
+
+static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
+			       u8 qos_map_set_len)
+{
+#ifdef CONFIG_ATHEROS_QOS_MAP
+	struct atheros_driver_data *drv = ctx;
+	struct ieee80211req_athdbg req;
+	struct ieee80211_qos_map *qos_map = &req.data.qos_map;
+	struct iwreq iwr;
+	int i, up_start;
+
+	if (qos_map_set_len < 16 || qos_map_set_len > 58 ||
+	    qos_map_set_len & 1) {
+		wpa_printf(MSG_ERROR, "Invalid QoS Map");
+		return -1;
+	} else {
+		memset(&req, 0, sizeof(struct ieee80211req_athdbg));
+		req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
+		iwr.u.data.pointer = (void *) &req;
+		iwr.u.data.length = sizeof(struct ieee80211req_athdbg);
+	}
+
+	qos_map->valid = 1;
+	qos_map->num_dscp_except = (qos_map_set_len - 16) / 2;
+	if (qos_map->num_dscp_except) {
+		for (i = 0; i < qos_map->num_dscp_except; i++) {
+			qos_map->dscp_exception[i].dscp	= qos_map_set[i * 2];
+			qos_map->dscp_exception[i].up =	qos_map_set[i * 2 + 1];
+		}
+	}
+
+	up_start = qos_map_set_len - 16;
+	for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) {
+		qos_map->up[i].low = qos_map_set[up_start + (i * 2)];
+		qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1];
+	}
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
+		perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
+		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
+			   __func__, drv->iface);
+		return -1;
+	}
+#endif /* CONFIG_ATHEROS_QOS_MAP */
+
+	return 0;
+}
+
 #if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
 static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
 				 size_t len)
@@ -906,16 +948,10 @@
 
 	switch (stype) {
 	case WLAN_FC_STYPE_ACTION:
-		if (&mgmt->u.action.category > buf + len)
-			break;
 		os_memset(&event, 0, sizeof(event));
-		event.rx_action.da = mgmt->da;
-		event.rx_action.sa = mgmt->sa;
-		event.rx_action.bssid = mgmt->bssid;
-		event.rx_action.category = mgmt->u.action.category;
-		event.rx_action.data = &mgmt->u.action.category;
-		event.rx_action.len = buf + len - event.rx_action.data;
-		wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = len;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
 		break;
 	default:
 		break;
@@ -1334,7 +1370,7 @@
 
 	while (1) {
 		os_memset(&iwr, 0, sizeof(iwr));
-		os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+		os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 
 		iwr.u.data.pointer = (void *) tbuf;
 		iwr.u.data.length = sizeof(tbuf);
@@ -1963,7 +1999,7 @@
 }
 
 
-#ifdef CONFIG_WNM
+#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
 static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
 			u8 *ie, u16 *len, enum wnm_oper oper)
 {
@@ -2116,7 +2152,7 @@
 		return -1;
 	}
 }
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
 
 
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
@@ -2150,7 +2186,8 @@
 	.add_sta_node    	= atheros_add_sta_node,
 #endif /* CONFIG_IEEE80211R */
 	.send_action		= atheros_send_action,
-#ifdef CONFIG_WNM
+#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
 	.wnm_oper		= atheros_wnm_oper,
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
+	.set_qos_map		= atheros_set_qos_map,
 };
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 4acb12b..ca64d5c 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -62,36 +62,12 @@
 	int	prev_privacy;	/* privacy state to restore on deinit */
 	int	prev_wpa;	/* wpa state to restore on deinit */
 	enum ieee80211_opmode opmode;	/* operation mode */
+	char	*event_buf;
+	size_t	event_buf_len;
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
 
-static enum ieee80211_opmode
-get80211opmode(struct bsd_driver_data *drv)
-{
-	struct ifmediareq ifmr;
-
-	(void) memset(&ifmr, 0, sizeof(ifmr));
-	(void) strncpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
-
-	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
-		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
-			if (ifmr.ifm_current & IFM_FLAG0)
-				return IEEE80211_M_AHDEMO;
-			else
-				return IEEE80211_M_IBSS;
-		}
-		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
-			return IEEE80211_M_HOSTAP;
-		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
-			return IEEE80211_M_MONITOR;
-		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
-			return IEEE80211_M_MBSS;
-	}
-	return IEEE80211_M_STA;
-}
-
-
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
@@ -310,21 +286,15 @@
 	return 0;
 }
 
-#ifdef HOSTAPD
-static int
-bsd_commit(void *priv)
-{
-	return bsd_ctrl_iface(priv, 1);
-}
-#endif /* HOSTAPD */
-
 static int
 bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
 	    size_t seq_len, const u8 *key, size_t key_len)
 {
 	struct ieee80211req_key wk;
+#ifdef IEEE80211_KEY_NOREPLAY
 	struct bsd_driver_data *drv = priv;
+#endif /* IEEE80211_KEY_NOREPLAY */
 
 	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
 		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -380,12 +350,14 @@
 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
 #ifndef HOSTAPD
+#ifdef IEEE80211_KEY_NOREPLAY
 	/*
 	 * Ignore replay failures in IBSS and AHDEMO mode.
 	 */
 	if (drv->opmode == IEEE80211_M_IBSS ||
 	    drv->opmode == IEEE80211_M_AHDEMO)
 		wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
+#endif /* IEEE80211_KEY_NOREPLAY */
 #endif /* HOSTAPD */
 	wk.ik_keylen = key_len;
 	if (seq) {
@@ -522,28 +494,6 @@
 	return bsd_ctrl_iface(priv, 1);
 }
 
-#ifdef HOSTAPD
-static int
-bsd_set_sta_authorized(void *priv, const u8 *addr,
-		       int total_flags, int flags_or, int flags_and)
-{
-	int authorized = -1;
-
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		authorized = 1;
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		authorized = 0;
-
-	if (authorized < 0)
-		return 0;
-
-	return bsd_send_mlme_param(priv, authorized ?
-				   IEEE80211_MLME_AUTHORIZE :
-				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
-}
-#endif /* HOSTAPD */
-
 static void
 bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
 {
@@ -636,7 +586,7 @@
 	return 0;
 }
 
-static int
+static size_t
 rtbuf_len(void)
 {
 	size_t len;
@@ -773,37 +723,26 @@
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
 	struct bsd_driver_data *drv = ctx;
-	char *buf;
 	struct if_announcemsghdr *ifan;
 	struct rt_msghdr *rtm;
 	struct ieee80211_michael_event *mic;
 	struct ieee80211_join_event *join;
 	struct ieee80211_leave_event *leave;
-	int n, len;
+	int n;
 	union wpa_event_data data;
 
-	len = rtbuf_len();
-
-	buf = os_malloc(len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
-		return;
-	}
-
-	n = read(sock, buf, len);
+	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
 				   __func__, strerror(errno));
-		os_free(buf);
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) buf;
+	rtm = (struct rt_msghdr *) drv->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
-		os_free(buf);
 		return;
 	}
 	ifan = (struct if_announcemsghdr *) rtm;
@@ -844,7 +783,6 @@
 		}
 		break;
 	}
-	os_free(buf);
 }
 
 static void
@@ -861,7 +799,15 @@
 
 	drv = os_zalloc(sizeof(struct bsd_driver_data));
 	if (drv == NULL) {
-		printf("Could not allocate memory for bsd driver data\n");
+		wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data");
+		return NULL;
+	}
+
+	drv->event_buf_len = rtbuf_len();
+
+	drv->event_buf = os_malloc(drv->event_buf_len);
+	if (drv->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
 		goto bad;
 	}
 
@@ -904,6 +850,7 @@
 		l2_packet_deinit(drv->sock_xmit);
 	if (drv->sock >= 0)
 		close(drv->sock);
+	os_free(drv->event_buf);
 	if (drv != NULL)
 		os_free(drv);
 	return NULL;
@@ -924,9 +871,37 @@
 		close(drv->sock);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
+	os_free(drv->event_buf);
 	os_free(drv);
 }
 
+
+static int
+bsd_commit(void *priv)
+{
+	return bsd_ctrl_iface(priv, 1);
+}
+
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr,
+		       int total_flags, int flags_or, int flags_and)
+{
+	int authorized = -1;
+
+	/* For now, only support setting Authorized flag */
+	if (flags_or & WPA_STA_AUTHORIZED)
+		authorized = 1;
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		authorized = 0;
+
+	if (authorized < 0)
+		return 0;
+
+	return bsd_send_mlme_param(priv, authorized ?
+				   IEEE80211_MLME_AUTHORIZE :
+				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
+}
 #else /* HOSTAPD */
 
 static int
@@ -1104,9 +1079,9 @@
 	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
 		return -1;
 
-	privacy = !(params->pairwise_suite == CIPHER_NONE &&
-	    params->group_suite == CIPHER_NONE &&
-	    params->key_mgmt_suite == KEY_MGMT_NONE &&
+	privacy = !(params->pairwise_suite == WPA_CIPHER_NONE &&
+	    params->group_suite == WPA_CIPHER_NONE &&
+	    params->key_mgmt_suite == WPA_KEY_MGMT_NONE &&
 	    params->wpa_ie_len == 0);
 	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
 
@@ -1202,7 +1177,6 @@
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
 	struct bsd_driver_data *drv = sock_ctx;
-	char *buf;
 	struct if_announcemsghdr *ifan;
 	struct if_msghdr *ifm;
 	struct rt_msghdr *rtm;
@@ -1210,30 +1184,20 @@
 	struct ieee80211_michael_event *mic;
 	struct ieee80211_leave_event *leave;
 	struct ieee80211_join_event *join;
-	int n, len;
+	int n;
 
-	len = rtbuf_len();
-
-	buf = os_malloc(len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
-		return;
-	}
-
-	n = read(sock, buf, len);
+	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
 				   __func__, strerror(errno));
-		os_free(buf);
 		return;
 	}
 
-	rtm = (struct rt_msghdr *) buf;
+	rtm = (struct rt_msghdr *) drv->event_buf;
 	if (rtm->rtm_version != RTM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
 			   rtm->rtm_version);
-		os_free(buf);
 		return;
 	}
 	os_memset(&event, 0, sizeof(event));
@@ -1248,7 +1212,6 @@
 		case IFAN_DEPARTURE:
 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
 		default:
-			os_free(buf);
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
@@ -1321,7 +1284,6 @@
 		}
 		break;
 	}
-	os_free(buf);
 }
 
 static void
@@ -1492,6 +1454,33 @@
 	return 0;
 }
 
+static enum ieee80211_opmode
+get80211opmode(struct bsd_driver_data *drv)
+{
+	struct ifmediareq ifmr;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+
+	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+			if (ifmr.ifm_current & IFM_FLAG0)
+				return IEEE80211_M_AHDEMO;
+			else
+				return IEEE80211_M_IBSS;
+		}
+		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+			return IEEE80211_M_HOSTAP;
+		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+			return IEEE80211_M_MONITOR;
+#ifdef IEEE80211_M_MBSS
+		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+			return IEEE80211_M_MBSS;
+#endif /* IEEE80211_M_MBSS */
+	}
+	return IEEE80211_M_STA;
+}
+
 static void *
 wpa_driver_bsd_init(void *ctx, const char *ifname)
 {
@@ -1502,6 +1491,15 @@
 	drv = os_zalloc(sizeof(*drv));
 	if (drv == NULL)
 		return NULL;
+
+	drv->event_buf_len = rtbuf_len();
+
+	drv->event_buf = os_malloc(drv->event_buf_len);
+	if (drv->event_buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+		goto fail1;
+	}
+
 	/*
 	 * NB: We require the interface name be mappable to an index.
 	 *     This implies we do not support having wpa_supplicant
@@ -1556,6 +1554,7 @@
 fail:
 	close(drv->sock);
 fail1:
+	os_free(drv->event_buf);
 	os_free(drv);
 	return NULL;
 #undef GETPARAM
@@ -1581,6 +1580,7 @@
 		l2_packet_deinit(drv->sock_xmit);
 	(void) close(drv->route);		/* ioctl socket */
 	(void) close(drv->sock);		/* event socket */
+	os_free(drv->event_buf);
 	os_free(drv);
 }
 
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 8d1d22e..3058cd5 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -49,7 +49,6 @@
 	E2S(TX_STATUS);
 	E2S(RX_FROM_UNKNOWN);
 	E2S(RX_MGMT);
-	E2S(RX_ACTION);
 	E2S(REMAIN_ON_CHANNEL);
 	E2S(CANCEL_REMAIN_ON_CHANNEL);
 	E2S(MLME_RX);
@@ -65,13 +64,6 @@
 	E2S(UNPROT_DEAUTH);
 	E2S(UNPROT_DISASSOC);
 	E2S(STATION_LOW_ACK);
-	E2S(P2P_DEV_FOUND);
-	E2S(P2P_GO_NEG_REQ_RX);
-	E2S(P2P_GO_NEG_COMPLETED);
-	E2S(P2P_PROV_DISC_REQUEST);
-	E2S(P2P_PROV_DISC_RESPONSE);
-	E2S(P2P_SD_REQUEST);
-	E2S(P2P_SD_RESPONSE);
 	E2S(IBSS_PEER_LOST);
 	E2S(DRIVER_GTK_REKEY);
 	E2S(SCHED_SCAN_STOPPED);
@@ -85,6 +77,8 @@
 	E2S(DFS_CAC_ABORTED);
 	E2S(DFS_NOP_FINISHED);
 	E2S(SURVEY);
+	E2S(SCAN_STARTED);
+	E2S(AVOID_FREQUENCIES);
 	}
 
 	return "UNKNOWN";
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index bb48011..1635c1f 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -1,5 +1,5 @@
 /*
- * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
+ * hostapd - driver interaction with MADWIFI 802.11 driver
  * Copyright (c) 2004, Sam Leffler <sam@errno.com>
  * Copyright (c) 2004, Video54 Technologies
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
@@ -7,10 +7,9 @@
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  *
- * While this driver wrapper supports both AP (hostapd) and station
- * (wpa_supplicant) operations, the station side is deprecated and
- * driver_wext.c should be used instead. This driver wrapper should only be
- * used with hostapd for AP mode functionality.
+ * This driver wrapper is only for hostapd AP mode functionality. Station
+ * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c
+ * wrapper.
  */
 
 #include "includes.h"
@@ -182,7 +181,7 @@
 #endif /* MADWIFI_NG */
 		int idx = op - first;
 		if (first <= op &&
-		    idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+		    idx < (int) ARRAY_SIZE(opnames) &&
 		    opnames[idx])
 			perror(opnames[idx]);
 		else
@@ -322,19 +321,16 @@
 			IEEE80211_AUTH_AUTO);
 	}
 	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
 		return -1;
 	}
 	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		wpa_printf(MSG_WARNING, "Error configuring WPA state!");
 		return -1;
 	}
 	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
 		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
 		return -1;
 	}
 
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 4656c1b..4953af6 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1074,8 +1074,8 @@
 		/* Try to continue anyway */
 	}
 
-	if (params->key_mgmt_suite == KEY_MGMT_NONE ||
-	    params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
+	if (params->key_mgmt_suite == WPA_KEY_MGMT_NONE ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
 		/* Re-set WEP keys if static WEP configuration is used. */
 		int i;
 		for (i = 0; i < 4; i++) {
@@ -1102,12 +1102,12 @@
 		priv_mode = Ndis802_11PrivFilterAcceptAll;
 	} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
 		priv_mode = Ndis802_11PrivFilter8021xWEP;
-		if (params->key_mgmt_suite == KEY_MGMT_PSK)
+		if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
 			auth_mode = Ndis802_11AuthModeWPA2PSK;
 		else
 			auth_mode = Ndis802_11AuthModeWPA2;
 #ifdef CONFIG_WPS
-	} else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
+	} else if (params->key_mgmt_suite == WPA_KEY_MGMT_WPS) {
 		auth_mode = Ndis802_11AuthModeOpen;
 		priv_mode = Ndis802_11PrivFilterAcceptAll;
 		if (params->wps == WPS_MODE_PRIVACY) {
@@ -1129,35 +1129,35 @@
 #endif /* CONFIG_WPS */
 	} else {
 		priv_mode = Ndis802_11PrivFilter8021xWEP;
-		if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+		if (params->key_mgmt_suite == WPA_KEY_MGMT_WPA_NONE)
 			auth_mode = Ndis802_11AuthModeWPANone;
-		else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+		else if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
 			auth_mode = Ndis802_11AuthModeWPAPSK;
 		else
 			auth_mode = Ndis802_11AuthModeWPA;
 	}
 
 	switch (params->pairwise_suite) {
-	case CIPHER_CCMP:
+	case WPA_CIPHER_CCMP:
 		encr = Ndis802_11Encryption3Enabled;
 		break;
-	case CIPHER_TKIP:
+	case WPA_CIPHER_TKIP:
 		encr = Ndis802_11Encryption2Enabled;
 		break;
-	case CIPHER_WEP40:
-	case CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+	case WPA_CIPHER_WEP104:
 		encr = Ndis802_11Encryption1Enabled;
 		break;
-	case CIPHER_NONE:
+	case WPA_CIPHER_NONE:
 #ifdef CONFIG_WPS
 		if (params->wps == WPS_MODE_PRIVACY) {
 			encr = Ndis802_11Encryption1Enabled;
 			break;
 		}
 #endif /* CONFIG_WPS */
-		if (params->group_suite == CIPHER_CCMP)
+		if (params->group_suite == WPA_CIPHER_CCMP)
 			encr = Ndis802_11Encryption3Enabled;
-		else if (params->group_suite == CIPHER_TKIP)
+		else if (params->group_suite == WPA_CIPHER_TKIP)
 			encr = Ndis802_11Encryption2Enabled;
 		else
 			encr = Ndis802_11EncryptionDisabled;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a3ff189..32a371d 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, 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>
@@ -28,6 +28,7 @@
 #include "common.h"
 #include "eloop.h"
 #include "utils/list.h"
+#include "common/qca-vendor.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "l2_packet/l2_packet.h"
@@ -109,6 +110,17 @@
 #endif /* CONFIG_LIBNL20 */
 
 
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+#endif /* ANDROID */
+
+
 static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
 	struct nl_handle *handle;
@@ -140,6 +152,31 @@
 }
 
 
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID	(intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID	(intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_handle **handle,
+					eloop_sock_handler handler,
+					void *eloop_data)
+{
+	nl_socket_set_nonblocking(*handle);
+	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+				 eloop_data, *handle);
+	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+{
+	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+	eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+	nl_destroy_handles(handle);
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
@@ -193,6 +230,7 @@
 	unsigned int added_bridge:1;
 	unsigned int in_deinit:1;
 	unsigned int wdev_id_set:1;
+	unsigned int added_if:1;
 
 	u8 addr[ETH_ALEN];
 
@@ -226,6 +264,11 @@
 	int operstate;
 
 	int scan_complete_events;
+	enum scan_states {
+		NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+		SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+		SCHED_SCAN_RESULTS
+	} scan_state;
 
 	struct nl_cb *nl_cb;
 
@@ -255,6 +298,9 @@
 	unsigned int use_monitor:1;
 	unsigned int ignore_next_local_disconnect:1;
 	unsigned int allow_p2p_device:1;
+	unsigned int hostapd:1;
+	unsigned int start_mode_ap:1;
+	unsigned int start_iface_up:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
@@ -264,21 +310,16 @@
 	struct wpa_driver_scan_filter *filter_ssids;
 	size_t num_filter_ssids;
 
-	struct i802_bss first_bss;
+	struct i802_bss *first_bss;
 
 	int eapol_tx_sock;
 
-#ifdef HOSTAPD
 	int eapol_sock; /* socket for EAPOL frames */
 
 	int default_if_indices[16];
 	int *if_indices;
 	int num_if_indices;
 
-	int last_freq;
-	int last_freq_ht;
-#endif /* HOSTAPD */
-
 	/* From failed authentication command */
 	int auth_freq;
 	u8 auth_bssid_[ETH_ALEN];
@@ -301,7 +342,8 @@
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
 				       enum nl80211_iftype nlmode);
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+				   const u8 *set_addr, int first);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 				   const u8 *addr, int cmd, u16 reason_code,
 				   int local_state_change);
@@ -320,41 +362,24 @@
 static int android_pno_start(struct i802_bss *bss,
 			     struct wpa_driver_scan_params *params);
 static int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+					 size_t buf_len);
 #endif /* ANDROID */
 #ifdef ANDROID_P2P
 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
 int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
 int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
-				  const struct wpabuf *proberesp,
-				  const struct wpabuf *assocresp);
+				 const struct wpabuf *proberesp,
+				 const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
 
-#endif
-#ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 					enum wpa_driver_if_type type,
 					const char *ifname);
-#else /* HOSTAPD */
-static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-}
-
-static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	return 0;
-}
-#endif /* HOSTAPD */
-#ifdef ANDROID
-extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
-					 size_t buf_len);
-#endif
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
 				       struct hostapd_freq_params *freq);
@@ -472,6 +497,11 @@
 	C2S(NL80211_CMD_FT_EVENT)
 	C2S(NL80211_CMD_CRIT_PROTOCOL_START)
 	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+	C2S(NL80211_CMD_GET_COALESCE)
+	C2S(NL80211_CMD_SET_COALESCE)
+	C2S(NL80211_CMD_CHANNEL_SWITCH)
+	C2S(NL80211_CMD_VENDOR)
+	C2S(NL80211_CMD_SET_QOS_MAP)
 	default:
 		return "NL80211_CMD_UNKNOWN";
 	}
@@ -479,6 +509,27 @@
 }
 
 
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+	switch (width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		return CHAN_WIDTH_20_NOHT;
+	case NL80211_CHAN_WIDTH_20:
+		return CHAN_WIDTH_20;
+	case NL80211_CHAN_WIDTH_40:
+		return CHAN_WIDTH_40;
+	case NL80211_CHAN_WIDTH_80:
+		return CHAN_WIDTH_80;
+	case NL80211_CHAN_WIDTH_80P80:
+		return CHAN_WIDTH_80P80;
+	case NL80211_CHAN_WIDTH_160:
+		return CHAN_WIDTH_160;
+	}
+	return CHAN_WIDTH_UNKNOWN;
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_AP ||
@@ -575,8 +626,14 @@
 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
 			  valid_handler, valid_data);
 
-	while (err > 0)
-		nl_recvmsgs(nl_handle, cb);
+	while (err > 0) {
+		int res = nl_recvmsgs(nl_handle, cb);
+		if (res) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: %s->nl_recvmsgs failed: %d",
+				   __func__, res);
+		}
+	}
  out:
 	nl_cb_put(cb);
 	nlmsg_free(msg);
@@ -594,10 +651,7 @@
 }
 
 
-#ifndef ANDROID
-static
-#endif
-int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 			      struct nl_msg *msg,
 			      int (*valid_handler)(struct nl_msg *, void *),
 			      void *valid_data)
@@ -772,7 +826,6 @@
 }
 
 
-#ifndef HOSTAPD
 static int nl80211_get_macaddr(struct i802_bss *bss)
 {
 	struct nl_msg *msg;
@@ -794,7 +847,6 @@
 	nlmsg_free(msg);
 	return NL80211_IFTYPE_UNSPECIFIED;
 }
-#endif /* HOSTAPD */
 
 
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
@@ -829,10 +881,15 @@
 static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
 {
 	struct nl80211_wiphy_data *w = eloop_ctx;
+	int res;
 
 	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
 
-	nl_recvmsgs(handle, w->nl_cb);
+	res = nl_recvmsgs(handle, w->nl_cb);
+	if (res) {
+		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+			   __func__, res);
+	}
 }
 
 
@@ -916,8 +973,7 @@
 		return NULL;
 	}
 
-	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
-				 nl80211_recv_beacons, w, w->nl_beacons);
+	nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
 
 	dl_list_add(&nl80211_wiphys, &w->list);
 
@@ -964,10 +1020,9 @@
 	if (!dl_list_empty(&w->bsss))
 		return;
 
-	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+	nl80211_destroy_eloop_handle(&w->nl_beacons);
 
 	nl_cb_put(w->nl_cb);
-	nl_destroy_handles(&w->nl_beacons);
 	dl_list_del(&w->list);
 	os_free(w);
 }
@@ -995,48 +1050,55 @@
 }
 
 
-static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
-					  char *buf, size_t len, int del)
+static void wpa_driver_nl80211_event_newlink(
+	struct wpa_driver_nl80211_data *drv, char *ifname)
 {
 	union wpa_event_data event;
 
-	os_memset(&event, 0, sizeof(event));
-	if (len > sizeof(event.interface_status.ifname))
-		len = sizeof(event.interface_status.ifname) - 1;
-	os_memcpy(event.interface_status.ifname, buf, len);
-	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
-		EVENT_INTERFACE_ADDED;
-
-	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
-		   del ? "DEL" : "NEW",
-		   event.interface_status.ifname,
-		   del ? "removed" : "added");
-
-	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
-		if (del) {
-			if (drv->if_removed) {
-				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
-					   "already set - ignore event");
-				return;
-			}
-			drv->if_removed = 1;
-		} else {
-			if (if_nametoindex(drv->first_bss.ifname) == 0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
-					   "does not exist - ignore "
-					   "RTM_NEWLINK",
-					   drv->first_bss.ifname);
-				return;
-			}
-			if (!drv->if_removed) {
-				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
-					   "already cleared - ignore event");
-				return;
-			}
-			drv->if_removed = 0;
+	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+		if (if_nametoindex(drv->first_bss->ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
+				   drv->first_bss->ifname);
+			return;
 		}
+		if (!drv->if_removed)
+			return;
+		wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
+			   drv->first_bss->ifname);
+		drv->if_removed = 0;
 	}
 
+	os_memset(&event, 0, sizeof(event));
+	os_strlcpy(event.interface_status.ifname, ifname,
+		   sizeof(event.interface_status.ifname));
+	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static void wpa_driver_nl80211_event_dellink(
+	struct wpa_driver_nl80211_data *drv, char *ifname)
+{
+	union wpa_event_data event;
+
+	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+		if (drv->if_removed) {
+			wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
+				   ifname);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
+			   ifname);
+		drv->if_removed = 1;
+	} else {
+		wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
+			   ifname);
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	os_strlcpy(event.interface_status.ifname, ifname,
+		   sizeof(event.interface_status.ifname));
+	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
 	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
 }
 
@@ -1053,8 +1115,8 @@
 	rta_len = RTA_ALIGN(sizeof(struct rtattr));
 	while (RTA_OK(attr, attrlen)) {
 		if (attr->rta_type == IFLA_IFNAME) {
-			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
-			    == 0)
+			if (os_strcmp(((char *) attr) + rta_len,
+				      drv->first_bss->ifname) == 0)
 				return 1;
 			else
 				break;
@@ -1075,7 +1137,7 @@
 	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
 			   "interface");
-		wpa_driver_nl80211_finish_drv_init(drv);
+		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
 		return 1;
 	}
 
@@ -1103,21 +1165,57 @@
 {
 	struct nl80211_global *global = ctx;
 	struct wpa_driver_nl80211_data *drv;
-	int attrlen, rta_len;
+	int attrlen;
 	struct rtattr *attr;
 	u32 brid = 0;
 	char namebuf[IFNAMSIZ];
+	char ifname[IFNAMSIZ + 1];
+	char extra[100], *pos, *end;
 
 	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 	if (!drv) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
-			   "ifindex %d", ifi->ifi_index);
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
+			   ifi->ifi_index);
 		return;
 	}
 
-	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
-		   "(%s%s%s%s)",
-		   drv->operstate, ifi->ifi_flags,
+	extra[0] = '\0';
+	pos = extra;
+	end = pos + sizeof(extra);
+	ifname[0] = '\0';
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+	while (RTA_OK(attr, attrlen)) {
+		switch (attr->rta_type) {
+		case IFLA_IFNAME:
+			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+				break;
+			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
+			ifname[RTA_PAYLOAD(attr)] = '\0';
+			break;
+		case IFLA_MASTER:
+			brid = nla_get_u32((struct nlattr *) attr);
+			pos += os_snprintf(pos, end - pos, " master=%u", brid);
+			break;
+		case IFLA_WIRELESS:
+			pos += os_snprintf(pos, end - pos, " wext");
+			break;
+		case IFLA_OPERSTATE:
+			pos += os_snprintf(pos, end - pos, " operstate=%u",
+					   nla_get_u32((struct nlattr *) attr));
+			break;
+		case IFLA_LINKMODE:
+			pos += os_snprintf(pos, end - pos, " linkmode=%u",
+					   nla_get_u32((struct nlattr *) attr));
+			break;
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+	extra[sizeof(extra) - 1] = '\0';
+
+	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)",
+		   ifi->ifi_index, ifname, extra, ifi->ifi_flags,
 		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
 		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
 		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
@@ -1126,7 +1224,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) {
+				   drv->first_bss->ifname) > 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
 			return;
@@ -1146,18 +1244,18 @@
 	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) {
+				   drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is down",
 				   namebuf);
-		} else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+		} else if (if_nametoindex(drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s does not exist",
-				   drv->first_bss.ifname);
+				   drv->first_bss->ifname);
 		} else if (drv->if_removed) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is marked "
-				   "removed", drv->first_bss.ifname);
+				   "removed", drv->first_bss->ifname);
 		} else {
 			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
 			drv->if_disabled = 0;
@@ -1174,24 +1272,15 @@
 	 */
 	if (drv->operstate == 1 &&
 	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
-	    !(ifi->ifi_flags & IFF_RUNNING))
+	    !(ifi->ifi_flags & IFF_RUNNING)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
 		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 				       -1, IF_OPER_UP);
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_nl80211_event_link(
-				drv,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len, 0);
-		} else if (attr->rta_type == IFLA_MASTER)
-			brid = nla_get_u32((struct nlattr *) attr);
-		attr = RTA_NEXT(attr, attrlen);
 	}
 
+	if (ifname[0])
+		wpa_driver_nl80211_event_newlink(drv, ifname);
+
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been added to bridge */
 		if_indextoname(brid, namebuf);
@@ -1208,32 +1297,40 @@
 {
 	struct nl80211_global *global = ctx;
 	struct wpa_driver_nl80211_data *drv;
-	int attrlen, rta_len;
+	int attrlen;
 	struct rtattr *attr;
 	u32 brid = 0;
+	char ifname[IFNAMSIZ + 1];
 
 	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 	if (!drv) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
-			   "foreign ifindex %d", ifi->ifi_index);
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
+			   ifi->ifi_index);
 		return;
 	}
 
+	ifname[0] = '\0';
+
 	attrlen = len;
 	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
 	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_nl80211_event_link(
-				drv,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len, 1);
-		} else if (attr->rta_type == IFLA_MASTER)
+		switch (attr->rta_type) {
+		case IFLA_IFNAME:
+			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+				break;
+			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
+			ifname[RTA_PAYLOAD(attr)] = '\0';
+			break;
+		case IFLA_MASTER:
 			brid = nla_get_u32((struct nlattr *) attr);
+			break;
+		}
 		attr = RTA_NEXT(attr, attrlen);
 	}
 
+	if (ifname[0])
+		wpa_driver_nl80211_event_dellink(drv, ifname);
+
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been removed from bridge */
 		char namebuf[IFNAMSIZ];
@@ -1453,35 +1550,96 @@
 }
 
 
-static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr *freq, struct nlattr *type)
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
 {
+	int freq1 = 0;
+
+	switch (convert2width(width)) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		return 0;
+	case CHAN_WIDTH_40:
+		freq1 = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		freq1 = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		freq1 = cf1 - 70;
+		break;
+	case CHAN_WIDTH_UNKNOWN:
+	case CHAN_WIDTH_80P80:
+		/* FIXME: implement this */
+		return 0;
+	}
+
+	return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr *ifindex, struct nlattr *freq,
+				 struct nlattr *type, struct nlattr *bw,
+				 struct nlattr *cf1, struct nlattr *cf2)
+{
+	struct i802_bss *bss;
 	union wpa_event_data data;
 	int ht_enabled = 1;
 	int chan_offset = 0;
+	int ifidx;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
 
-	if (!freq || !type)
+	if (!freq)
 		return;
 
-	switch (nla_get_u32(type)) {
-	case NL80211_CHAN_NO_HT:
-		ht_enabled = 0;
-		break;
-	case NL80211_CHAN_HT20:
-		break;
-	case NL80211_CHAN_HT40PLUS:
-		chan_offset = 1;
-		break;
-	case NL80211_CHAN_HT40MINUS:
-		chan_offset = -1;
-		break;
+	ifidx = nla_get_u32(ifindex);
+	for (bss = drv->first_bss; bss; bss = bss->next)
+		if (bss->ifindex == ifidx)
+			break;
+
+	if (bss == NULL) {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+			   ifidx);
+		return;
 	}
 
+	if (type) {
+		switch (nla_get_u32(type)) {
+		case NL80211_CHAN_NO_HT:
+			ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			chan_offset = -1;
+			break;
+		}
+	} else if (bw && cf1) {
+		/* This can happen for example with VHT80 ch switch */
+		chan_offset = calculate_chan_offset(nla_get_u32(bw),
+						    nla_get_u32(freq),
+						    nla_get_u32(cf1),
+						    cf2 ? nla_get_u32(cf2) : 0);
+	} else {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+	}
+
+	os_memset(&data, 0, sizeof(data));
 	data.ch_switch.freq = nla_get_u32(freq);
 	data.ch_switch.ht_enabled = ht_enabled;
 	data.ch_switch.ch_offset = chan_offset;
+	if (bw)
+		data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+	if (cf1)
+		data.ch_switch.cf1 = nla_get_u32(cf1);
+	if (cf2)
+		data.ch_switch.cf2 = nla_get_u32(cf2);
+
+	bss->freq = data.ch_switch.freq;
 
 	wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
@@ -1520,11 +1678,12 @@
 	union wpa_event_data event;
 	u16 fc, stype;
 	int ssi_signal = 0;
+	int rx_freq = 0;
 
 	wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
 	mgmt = (const struct ieee80211_mgmt *) frame;
 	if (len < 24) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
+		wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
 		return;
 	}
 
@@ -1536,23 +1695,16 @@
 
 	os_memset(&event, 0, sizeof(event));
 	if (freq) {
-		event.rx_action.freq = nla_get_u32(freq);
-		drv->last_mgmt_freq = event.rx_action.freq;
+		event.rx_mgmt.freq = nla_get_u32(freq);
+		rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
 	}
-	if (stype == WLAN_FC_STYPE_ACTION) {
-		event.rx_action.da = mgmt->da;
-		event.rx_action.sa = mgmt->sa;
-		event.rx_action.bssid = mgmt->bssid;
-		event.rx_action.category = mgmt->u.action.category;
-		event.rx_action.data = &mgmt->u.action.category + 1;
-		event.rx_action.len = frame + len - event.rx_action.data;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
-	} else {
-		event.rx_mgmt.frame = frame;
-		event.rx_mgmt.frame_len = len;
-		event.rx_mgmt.ssi_signal = ssi_signal;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-	}
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u",
+		   rx_freq, ssi_signal, stype, (unsigned int) len);
+	event.rx_mgmt.frame = frame;
+	event.rx_mgmt.frame_len = len;
+	event.rx_mgmt.ssi_signal = ssi_signal;
+	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
 }
 
 
@@ -1653,7 +1805,7 @@
 
 	if (type == EVENT_DISASSOC) {
 		event.disassoc_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
 		event.disassoc_info.addr = bssid;
 		event.disassoc_info.reason_code = reason_code;
 		if (frame + len > mgmt->u.disassoc.variable) {
@@ -1663,7 +1815,7 @@
 		}
 	} else {
 		event.deauth_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
 		event.deauth_info.addr = bssid;
 		event.deauth_info.reason_code = reason_code;
 		if (frame + len > mgmt->u.deauth.variable) {
@@ -1836,8 +1988,6 @@
 static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *tb[])
 {
-	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
 	if (tb[NL80211_ATTR_MAC] == NULL) {
 		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
 			   "event");
@@ -1845,10 +1995,6 @@
 	}
 	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
 
-	/* register for any AUTH message */
-	nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
-			       type, NULL, 0);
-
 	drv->associated = 1;
 	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
 		   MAC2STR(drv->bssid));
@@ -1962,21 +2108,36 @@
 				&info->ssids[info->num_ssids];
 			s->ssid = nla_data(nl);
 			s->ssid_len = nla_len(nl);
+			wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+				   wpa_ssid_txt(s->ssid, s->ssid_len));
 			info->num_ssids++;
 			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
 				break;
 		}
 	}
 	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+		char msg[200], *pos, *end;
+		int res;
+
+		pos = msg;
+		end = pos + sizeof(msg);
+		*pos = '\0';
+
 		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
 		{
 			freqs[num_freqs] = nla_get_u32(nl);
+			res = os_snprintf(pos, end - pos, " %d",
+					  freqs[num_freqs]);
+			if (res > 0 && end - pos > res)
+				pos += res;
 			num_freqs++;
 			if (num_freqs == MAX_REPORT_FREQS - 1)
 				break;
 		}
 		info->freqs = freqs;
 		info->num_freqs = num_freqs;
+		wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+			   msg);
 	}
 	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
 }
@@ -2514,11 +2675,43 @@
 		return;
 
 	os_memset(&data, 0, sizeof(data));
-	data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
-	event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+	data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
 
-	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 (event_type) {
 	case NL80211_RADAR_DETECTED:
@@ -2559,10 +2752,119 @@
 }
 
 
+static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
+				   const u8 *data, size_t len)
+{
+	u32 i, count;
+	union wpa_event_data event;
+	struct wpa_freq_range *range = NULL;
+	const struct qca_avoid_freq_list *freq_range;
+
+	freq_range = (const struct qca_avoid_freq_list *) data;
+	if (len < sizeof(freq_range->count))
+		return;
+
+	count = freq_range->count;
+	if (len < sizeof(freq_range->count) +
+	    count * sizeof(struct qca_avoid_freq_range)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
+			   (unsigned int) len);
+		return;
+	}
+
+	if (count > 0) {
+		range = os_calloc(count, sizeof(struct wpa_freq_range));
+		if (range == NULL)
+			return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	for (i = 0; i < count; i++) {
+		unsigned int idx = event.freq_range.num;
+		range[idx].min = freq_range->range[i].start_freq;
+		range[idx].max = freq_range->range[i].end_freq;
+		wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
+			   range[idx].min, range[idx].max);
+		if (range[idx].min > range[idx].max) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
+			continue;
+		}
+		event.freq_range.num++;
+	}
+	event.freq_range.range = range;
+
+	wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
+
+	os_free(range);
+}
+
+
+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_AVOID_FREQUENCY:
+		qca_nl80211_avoid_freq(drv, data, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore unsupported QCA vendor event %u",
+			   subcmd);
+		break;
+	}
+}
+
+
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr **tb)
+{
+	u32 vendor_id, subcmd, wiphy = 0;
+	int wiphy_idx;
+	u8 *data = NULL;
+	size_t len = 0;
+
+	if (!tb[NL80211_ATTR_VENDOR_ID] ||
+	    !tb[NL80211_ATTR_VENDOR_SUBCMD])
+		return;
+
+	vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
+	subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
+
+	if (tb[NL80211_ATTR_WIPHY])
+		wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
+		   wiphy, vendor_id, subcmd);
+
+	if (tb[NL80211_ATTR_VENDOR_DATA]) {
+		data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
+		len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
+	}
+
+	wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
+	if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
+			   wiphy, wiphy_idx);
+		return;
+	}
+
+	switch (vendor_id) {
+	case OUI_QCA:
+		nl80211_vendor_event_qca(drv, subcmd, data, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
+		break;
+	}
+}
+
+
 static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				 struct nlattr **tb)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data data;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
 		   cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2570,7 +2872,7 @@
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
 	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
 	     cmd == NL80211_CMD_SCAN_ABORTED)) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
+		wpa_driver_nl80211_set_mode(drv->first_bss,
 					    drv->ap_scan_as_station);
 		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
@@ -2578,17 +2880,22 @@
 	switch (cmd) {
 	case NL80211_CMD_TRIGGER_SCAN:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+		drv->scan_state = SCAN_STARTED;
+		wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
 		break;
 	case NL80211_CMD_START_SCHED_SCAN:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+		drv->scan_state = SCHED_SCAN_STARTED;
 		break;
 	case NL80211_CMD_SCHED_SCAN_STOPPED:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+		drv->scan_state = SCHED_SCAN_STOPPED;
 		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
 		break;
 	case NL80211_CMD_NEW_SCAN_RESULTS:
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: New scan results available");
+		drv->scan_state = SCAN_COMPLETED;
 		drv->scan_complete_events = 1;
 		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
 				     drv->ctx);
@@ -2597,10 +2904,12 @@
 	case NL80211_CMD_SCHED_SCAN_RESULTS:
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: New sched scan results available");
+		drv->scan_state = SCHED_SCAN_RESULTS;
 		send_scan_event(drv, 0, tb);
 		break;
 	case NL80211_CMD_SCAN_ABORTED:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+		drv->scan_state = SCAN_ABORTED;
 		/*
 		 * Need to indicate that scan results are available in order
 		 * not to make wpa_supplicant stop its scanning.
@@ -2631,8 +2940,13 @@
 				   tb[NL80211_ATTR_RESP_IE]);
 		break;
 	case NL80211_CMD_CH_SWITCH_NOTIFY:
-		mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
-				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+		mlme_event_ch_switch(drv,
+				     tb[NL80211_ATTR_IFINDEX],
+				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+				     tb[NL80211_ATTR_CHANNEL_WIDTH],
+				     tb[NL80211_ATTR_CENTER_FREQ1],
+				     tb[NL80211_ATTR_CENTER_FREQ2]);
 		break;
 	case NL80211_CMD_DISCONNECT:
 		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -2656,13 +2970,40 @@
 		break;
 	case NL80211_CMD_REG_CHANGE:
 		wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+		if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+			break;
+		os_memset(&data, 0, sizeof(data));
+		switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+		case NL80211_REGDOM_SET_BY_CORE:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_CORE;
+			break;
+		case NL80211_REGDOM_SET_BY_USER:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_USER;
+			break;
+		case NL80211_REGDOM_SET_BY_DRIVER:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_DRIVER;
+			break;
+		case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+			data.channel_list_changed.initiator =
+				REGDOM_SET_BY_COUNTRY_IE;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+				   nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+			break;
+		}
 		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-				     NULL);
+				     &data);
 		break;
 	case NL80211_CMD_REG_BEACON_HINT:
 		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+		os_memset(&data, 0, sizeof(data));
+		data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
 		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-				     NULL);
+				     &data);
 		break;
 	case NL80211_CMD_NEW_STATION:
 		nl80211_new_station_event(drv, tb);
@@ -2694,6 +3035,9 @@
 	case NL80211_CMD_STOP_AP:
 		nl80211_stop_ap(drv, tb);
 		break;
+	case NL80211_CMD_VENDOR:
+		nl80211_vendor_event(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
@@ -2716,7 +3060,7 @@
 	if (tb[NL80211_ATTR_IFINDEX]) {
 		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-		for (bss = &drv->first_bss; bss; bss = bss->next)
+		for (bss = drv->first_bss; bss; bss = bss->next)
 			if (ifidx == -1 || ifidx == bss->ifindex) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
@@ -2727,7 +3071,7 @@
 	} else if (tb[NL80211_ATTR_WDEV]) {
 		u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
 		wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
-		for (bss = &drv->first_bss; bss; bss = bss->next) {
+		for (bss = drv->first_bss; bss; bss = bss->next) {
 			if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
@@ -2765,7 +3109,7 @@
 
 	dl_list_for_each_safe(drv, tmp, &global->interfaces,
 			      struct wpa_driver_nl80211_data, list) {
-		for (bss = &drv->first_bss; bss; bss = bss->next) {
+		for (bss = drv->first_bss; bss; bss = bss->next) {
 			if ((ifidx == -1 && !wdev_id_set) ||
 			    ifidx == bss->ifindex ||
 			    (wdev_id_set && bss->wdev_id_set &&
@@ -2822,10 +3166,15 @@
 					     void *handle)
 {
 	struct nl_cb *cb = eloop_ctx;
+	int res;
 
 	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
-	nl_recvmsgs(handle, cb);
+	res = nl_recvmsgs(handle, cb);
+	if (res) {
+		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+			   __func__, res);
+	}
 }
 
 
@@ -2865,6 +3214,44 @@
 }
 
 
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+	char *alpha2 = arg;
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
+		wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+		return NL_SKIP;
+	}
+	os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+	return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+	alpha2[0] = '\0';
+	ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+	if (!alpha2[0])
+		ret = -1;
+
+	return ret;
+}
+
+
 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
 {
 	u32 *feat = arg;
@@ -2917,6 +3304,8 @@
 	unsigned int p2p_go_supported:1;
 	unsigned int p2p_client_supported:1;
 	unsigned int p2p_concurrent:1;
+	unsigned int channel_switch_supported:1;
+	unsigned int set_qos_map_supported:1;
 };
 
 
@@ -3074,6 +3463,68 @@
 		case NL80211_CMD_PROBE_CLIENT:
 			info->poll_command_supported = 1;
 			break;
+		case NL80211_CMD_CHANNEL_SWITCH:
+			info->channel_switch_supported = 1;
+			break;
+		case NL80211_CMD_SET_QOS_MAP:
+			info->set_qos_map_supported = 1;
+			break;
+		}
+	}
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+				     struct nlattr *tb)
+{
+	int i, num;
+	u32 *ciphers;
+
+	if (tb == NULL)
+		return;
+
+	num = nla_len(tb) / sizeof(u32);
+	ciphers = nla_data(tb);
+	for (i = 0; i < num; i++) {
+		u32 c = ciphers[i];
+
+		wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+			   c >> 24, (c >> 16) & 0xff,
+			   (c >> 8) & 0xff, c & 0xff);
+		switch (c) {
+		case WLAN_CIPHER_SUITE_CCMP_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+			break;
+		case WLAN_CIPHER_SUITE_GCMP_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+			break;
+		case WLAN_CIPHER_SUITE_GCMP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+			break;
+		case WLAN_CIPHER_SUITE_TKIP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+			break;
+		case WLAN_CIPHER_SUITE_WEP104:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+			break;
+		case WLAN_CIPHER_SUITE_WEP40:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+			break;
+		case WLAN_CIPHER_SUITE_AES_CMAC:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+			break;
 		}
 	}
 }
@@ -3156,7 +3607,7 @@
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
 	if (tb[NL80211_ATTR_WIPHY_NAME])
-		os_strncpy(drv->phyname,
+		os_strlcpy(drv->phyname,
 			   nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
 			   sizeof(drv->phyname));
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
@@ -3178,6 +3629,7 @@
 	wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
 	wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
 	wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+	wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
 
 	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
 		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -3230,6 +3682,38 @@
 		}
 	}
 
+	if (tb[NL80211_ATTR_VENDOR_DATA]) {
+		struct nlattr *nl;
+		int rem;
+
+		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
+			struct nl80211_vendor_cmd_info *vinfo;
+			if (nla_len(nl) != sizeof(*vinfo)) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+				continue;
+			}
+			vinfo = nla_data(nl);
+			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+				   vinfo->vendor_id, vinfo->subcmd);
+		}
+	}
+
+	if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
+		struct nlattr *nl;
+		int rem;
+
+		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
+			struct nl80211_vendor_cmd_info *vinfo;
+			if (nla_len(nl) != sizeof(*vinfo)) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+				continue;
+			}
+			vinfo = nla_data(nl);
+			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
+				   vinfo->vendor_id, vinfo->subcmd);
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -3255,7 +3739,7 @@
 		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 
 	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
@@ -3288,6 +3772,9 @@
 	if (!drv->capa.max_remain_on_chan)
 		drv->capa.max_remain_on_chan = 5000;
 
+	if (info->channel_switch_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+
 	return 0;
 nla_put_failure:
 	nlmsg_free(msg);
@@ -3305,15 +3792,10 @@
 		return -1;
 
 	drv->has_capability = 1;
-	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
 	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;
-	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-		WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP |
-		WPA_DRIVER_CAPA_ENC_CCMP;
 	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
@@ -3335,21 +3817,14 @@
 	drv->device_ap_sme = info.device_ap_sme;
 	drv->poll_command_supported = info.poll_command_supported;
 	drv->data_tx_status = info.data_tx_status;
+	if (info.set_qos_map_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
 
-#ifdef ANDROID_P2P
-	if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
-		/* Driver is new enough to support monitorless mode*/
-		wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
-			  "enough to support monitor-less mode");
-		drv->use_monitor = 0;
-	}
-#else
 	/*
 	 * If poll command and tx status are supported, mac80211 is new enough
 	 * to have everything we need to not need monitor interfaces.
 	 */
 	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-#endif
 
 	if (drv->device_ap_sme && drv->use_monitor) {
 		/*
@@ -3469,14 +3944,24 @@
 		/* Continue without regulatory events */
 	}
 
+	ret = nl_get_multicast_id(global, "nl80211", "vendor");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_event, ret);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
+			   "membership for vendor events: %d (%s)",
+			   ret, strerror(-ret));
+		/* Continue without vendor events */
+	}
+
 	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
 		  no_seq_check, NULL);
 	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
 		  process_global_event, global);
 
-	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
-				 wpa_driver_nl80211_event_receive,
-				 global->nl_cb, global->nl_event);
+	nl80211_register_eloop_read(&global->nl_event,
+				    wpa_driver_nl80211_event_receive,
+				    global->nl_cb);
 
 	return 0;
 
@@ -3520,7 +4005,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = ctx;
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-	if (i802_set_iface_flags(&drv->first_bss, 1)) {
+	if (i802_set_iface_flags(drv->first_bss, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
 			   "after rfkill unblock");
 		return;
@@ -3610,16 +4095,9 @@
 }
 
 
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * @global_priv: private driver global data from global_init()
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
-				      void *global_priv)
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+					  void *global_priv, int hostapd,
+					  const u8 *set_addr)
 {
 	struct wpa_driver_nl80211_data *drv;
 	struct rfkill_config *rcfg;
@@ -3632,7 +4110,17 @@
 		return NULL;
 	drv->global = global_priv;
 	drv->ctx = ctx;
-	bss = &drv->first_bss;
+	drv->hostapd = !!hostapd;
+	drv->eapol_sock = -1;
+	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+	drv->if_indices = drv->default_if_indices;
+
+	drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+	if (!drv->first_bss) {
+		os_free(drv);
+		return NULL;
+	}
+	bss = drv->first_bss;
 	bss->drv = drv;
 	bss->ctx = ctx;
 
@@ -3663,7 +4151,10 @@
 		os_free(rcfg);
 	}
 
-	if (wpa_driver_nl80211_finish_drv_init(drv))
+	if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
+		drv->start_iface_up = 1;
+
+	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
 		goto failed;
 
 	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -3701,6 +4192,21 @@
 }
 
 
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+				      void *global_priv)
+{
+	return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+}
+
+
 static int nl80211_register_frame(struct i802_bss *bss,
 				  struct nl_handle *nl_handle,
 				  u16 type, const u8 *match, size_t match_len)
@@ -3708,15 +4214,16 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret = -1;
+	char buf[30];
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
-		   type, nl_handle);
-	wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
-		    match, match_len);
+	buf[0] = '\0';
+	wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
+	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s",
+		   type, nl_handle, buf);
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
@@ -3757,14 +4264,18 @@
 	if (bss->nl_mgmt == NULL)
 		return -1;
 
-	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
-				 wpa_driver_nl80211_event_receive, bss->nl_cb,
-				 bss->nl_mgmt);
-
 	return 0;
 }
 
 
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+	nl80211_register_eloop_read(&bss->nl_mgmt,
+				    wpa_driver_nl80211_event_receive,
+				    bss->nl_cb);
+}
+
+
 static int nl80211_register_action_frame(struct i802_bss *bss,
 					 const u8 *match, size_t match_len)
 {
@@ -3777,67 +4288,94 @@
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = 0;
 
 	if (nl80211_alloc_mgmt_handle(bss))
 		return -1;
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
 		   "handle %p", bss->nl_mgmt);
 
+	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+		u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+		/* register for any AUTH message */
+		nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+	}
+
+#ifdef CONFIG_INTERWORKING
+	/* QoS Map Configure */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
+		ret = -1;
+#endif /* CONFIG_INTERWORKING */
 #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
 	/* GAS Initial Request */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
-		return -1;
+		ret = -1;
 	/* GAS Initial Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
-		return -1;
+		ret = -1;
 	/* GAS Comeback Request */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
-		return -1;
+		ret = -1;
 	/* GAS Comeback Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
-		return -1;
+		ret = -1;
+	/* Protected GAS Initial Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
+		ret = -1;
+	/* Protected GAS Initial Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
+		ret = -1;
+	/* Protected GAS Comeback Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
+		ret = -1;
+	/* Protected GAS Comeback Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
+		ret = -1;
 #endif /* CONFIG_P2P || CONFIG_INTERWORKING */
 #ifdef CONFIG_P2P
 	/* P2P Public Action */
 	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
 					  6) < 0)
-		return -1;
+		ret = -1;
 	/* P2P Action */
 	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x7f\x50\x6f\x9a\x09",
 					  5) < 0)
-		return -1;
+		ret = -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_IEEE80211W
 	/* SA Query Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
-		return -1;
+		ret = -1;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_TDLS
 	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
 		/* TDLS Discovery Response */
 		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
 		    0)
-			return -1;
+			ret = -1;
 	}
 #endif /* CONFIG_TDLS */
 
 	/* FT Action frames */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
-		return -1;
+		ret = -1;
 	else
 		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
 			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
 	/* WNM - BSS Transition Management Request */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
-		return -1;
+		ret = -1;
 	/* WNM-Sleep Mode Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
-		return -1;
+		ret = -1;
 
-	return 0;
+	nl80211_mgmt_handle_register_eloop(bss);
+
+	return ret;
 }
 
 
@@ -3894,7 +4432,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
 		   "handle %p", bss->nl_mgmt);
 
-	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(stypes); i++) {
 		if (nl80211_register_frame(bss, bss->nl_mgmt,
 					   (WLAN_FC_TYPE_MGMT << 2) |
 					   (stypes[i] << 4),
@@ -3909,10 +4447,10 @@
 	if (nl80211_get_wiphy_data_ap(bss) == NULL)
 		goto out_err;
 
+	nl80211_mgmt_handle_register_eloop(bss);
 	return 0;
 
 out_err:
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
 	nl_destroy_handles(&bss->nl_mgmt);
 	return -1;
 }
@@ -3931,10 +4469,10 @@
 				   NULL, 0) < 0)
 		goto out_err;
 
+	nl80211_mgmt_handle_register_eloop(bss);
 	return 0;
 
 out_err:
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
 	nl_destroy_handles(&bss->nl_mgmt);
 	return -1;
 }
@@ -3946,8 +4484,7 @@
 		return;
 	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
 		   "(%s)", bss->nl_mgmt, reason);
-	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
-	nl_destroy_handles(&bss->nl_mgmt);
+	nl80211_destroy_eloop_handle(&bss->nl_mgmt);
 
 	nl80211_put_wiphy_data_ap(bss);
 }
@@ -3977,7 +4514,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
 		   bss->ifname, (long long unsigned int) bss->wdev_id,
-		   strerror(ret));
+		   strerror(-ret));
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -4007,7 +4544,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
 		   start ? "Start" : "Stop",
 		   bss->ifname, (long long unsigned int) bss->wdev_id,
-		   strerror(ret));
+		   strerror(-ret));
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -4031,13 +4568,12 @@
 
 
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+				   const u8 *set_addr, int first)
 {
-#ifndef HOSTAPD
-	enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
-#endif /* HOSTAPD */
-	struct i802_bss *bss = &drv->first_bss;
+	struct i802_bss *bss = drv->first_bss;
 	int send_rfkill_event = 0;
+	enum nl80211_iftype nlmode;
 
 	drv->ifindex = if_nametoindex(bss->ifname);
 	bss->ifindex = drv->ifindex;
@@ -4054,20 +4590,26 @@
 	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
 		   bss->ifname, drv->phyname);
 
-#ifndef HOSTAPD
-	if (bss->if_dynamic)
-		nlmode = nl80211_get_ifmode(bss);
+	if (set_addr &&
+	    (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+	     linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				set_addr)))
+		return -1;
 
-	/*
-	 * Make sure the interface starts up in station mode unless this is a
-	 * dynamically added interface (e.g., P2P) that was already configured
-	 * with proper iftype.
-	 */
+	if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+		drv->start_mode_ap = 1;
+
+	if (drv->hostapd)
+		nlmode = NL80211_IFTYPE_AP;
+	else if (bss->if_dynamic)
+		nlmode = nl80211_get_ifmode(bss);
+	else
+		nlmode = NL80211_IFTYPE_STATION;
+
 	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
 		return -1;
 	}
-	drv->nlmode = nlmode;
 
 	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
 		int ret = nl80211_set_p2pdev(bss, 1);
@@ -4091,9 +4633,9 @@
 		}
 	}
 
-	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
-			       1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
+	if (!drv->hostapd)
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+				       1, IF_OPER_DORMANT);
 
 	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 			       bss->addr))
@@ -4116,6 +4658,8 @@
 	if (!msg)
 		return -ENOMEM;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+		   drv->ifindex);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -4164,15 +4708,6 @@
 	if (is_ap_interface(drv->nlmode))
 		wpa_driver_nl80211_del_beacon(drv);
 
-#ifdef HOSTAPD
-	if (drv->last_freq_ht) {
-		/* Clear HT flags from the driver */
-		struct hostapd_freq_params freq;
-		os_memset(&freq, 0, sizeof(freq));
-		freq.freq = drv->last_freq;
-		wpa_driver_nl80211_set_freq(bss, &freq);
-	}
-
 	if (drv->eapol_sock >= 0) {
 		eloop_unregister_read_sock(drv->eapol_sock);
 		close(drv->eapol_sock);
@@ -4180,7 +4715,6 @@
 
 	if (drv->if_indices != drv->default_if_indices)
 		os_free(drv->if_indices);
-#endif /* HOSTAPD */
 
 	if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -4191,9 +4725,12 @@
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(void) i802_set_iface_flags(bss, 0);
+	if (!drv->start_iface_up)
+		(void) i802_set_iface_flags(bss, 0);
 	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
-		wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+		if (!drv->hostapd || !drv->start_mode_ap)
+			wpa_driver_nl80211_set_mode(bss,
+						    NL80211_IFTYPE_STATION);
 		nl80211_mgmt_unsubscribe(bss, "deinit");
 	} else {
 		nl80211_mgmt_unsubscribe(bss, "deinit");
@@ -4201,7 +4738,7 @@
 	}
 	nl_cb_put(drv->nl_cb);
 
-	nl80211_destroy_bss(&drv->first_bss);
+	nl80211_destroy_bss(drv->first_bss);
 
 	os_free(drv->filter_ssids);
 
@@ -4212,6 +4749,7 @@
 
 	os_free(drv->extended_capa);
 	os_free(drv->extended_capa_mask);
+	os_free(drv->first_bss);
 	os_free(drv);
 }
 
@@ -4228,7 +4766,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = eloop_ctx;
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
+		wpa_driver_nl80211_set_mode(drv->first_bss,
 					    drv->ap_scan_as_station);
 		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
@@ -4299,6 +4837,12 @@
 	params->filter_ssids = NULL;
 	drv->num_filter_ssids = params->num_filter_ssids;
 
+	if (params->only_new_results) {
+		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
+		NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS,
+			    NL80211_SCAN_FLAG_FLUSH);
+	}
+
 	return msg;
 
 fail:
@@ -4356,8 +4900,9 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
-		if (is_ap_interface(drv->nlmode)) {
+		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+			enum nl80211_iftype old_mode = drv->nlmode;
+
 			/*
 			 * mac80211 does not allow scan requests in AP mode, so
 			 * try to do this in station mode.
@@ -4372,15 +4917,13 @@
 			}
 
 			/* Restore AP mode when processing scan results */
-			drv->ap_scan_as_station = drv->nlmode;
+			drv->ap_scan_as_station = old_mode;
 			ret = 0;
 		} else
 			goto nla_put_failure;
-#else /* HOSTAPD */
-		goto nla_put_failure;
-#endif /* HOSTAPD */
 	}
 
+	drv->scan_state = SCAN_REQUESTED;
 	/* Not all drivers generate "scan completed" wireless event, so try to
 	 * read results after a timeout. */
 	timeout = 10;
@@ -4456,10 +4999,20 @@
 			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
+			if (params->filter_rssi)
+				NLA_PUT_U32(msg,
+					    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+					    params->filter_rssi);
 
 			nla_nest_end(msg, match_set_ssid);
 		}
 
+		/*
+		 * Due to backward compatibility code, newer kernels treat this
+		 * matchset (with only an RSSI filter) as the default for all
+		 * other matchsets, unless it's the only one, in which case the
+		 * matchset will actually allow all SSIDs above the RSSI.
+		 */
 		if (params->filter_rssi) {
 			struct nlattr *match_set_rssi;
 			match_set_rssi = nla_nest_start(msg, 0);
@@ -4712,7 +5265,8 @@
 	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
 	 * not use frequency as a separate key in the BSS table, so filter out
 	 * duplicated entries. Prefer associated BSS entry in such a case in
-	 * order to get the correct frequency into the BSS table.
+	 * order to get the correct frequency into the BSS table. Similarly,
+	 * prefer newer entries over older.
 	 */
 	for (i = 0; i < res->num; i++) {
 		const u8 *s1, *s2;
@@ -4730,8 +5284,9 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
 			   "for " MACSTR, MAC2STR(r->bssid));
 
-		if ((r->flags & WPA_SCAN_ASSOCIATED) &&
-		    !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
+		if (((r->flags & WPA_SCAN_ASSOCIATED) &&
+		     !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
+		    r->age < res->res[i]->age) {
 			os_free(res->res[i]);
 			res->res[i] = r;
 		} else
@@ -4832,7 +5387,7 @@
 		goto nla_put_failure;
 
 	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 
 	arg.drv = drv;
@@ -4897,6 +5452,95 @@
 }
 
 
+static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
+{
+	switch (alg) {
+	case WPA_ALG_WEP:
+		if (key_len == 5)
+			return WLAN_CIPHER_SUITE_WEP40;
+		return WLAN_CIPHER_SUITE_WEP104;
+	case WPA_ALG_TKIP:
+		return WLAN_CIPHER_SUITE_TKIP;
+	case WPA_ALG_CCMP:
+		return WLAN_CIPHER_SUITE_CCMP;
+	case WPA_ALG_GCMP:
+		return WLAN_CIPHER_SUITE_GCMP;
+	case WPA_ALG_CCMP_256:
+		return WLAN_CIPHER_SUITE_CCMP_256;
+	case WPA_ALG_GCMP_256:
+		return WLAN_CIPHER_SUITE_GCMP_256;
+	case WPA_ALG_IGTK:
+		return WLAN_CIPHER_SUITE_AES_CMAC;
+	case WPA_ALG_BIP_GMAC_128:
+		return WLAN_CIPHER_SUITE_BIP_GMAC_128;
+	case WPA_ALG_BIP_GMAC_256:
+		return WLAN_CIPHER_SUITE_BIP_GMAC_256;
+	case WPA_ALG_BIP_CMAC_256:
+		return WLAN_CIPHER_SUITE_BIP_CMAC_256;
+	case WPA_ALG_SMS4:
+		return WLAN_CIPHER_SUITE_SMS4;
+	case WPA_ALG_KRK:
+		return WLAN_CIPHER_SUITE_KRK;
+	case WPA_ALG_NONE:
+	case WPA_ALG_PMK:
+		wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
+			   alg);
+		return 0;
+	}
+
+	wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
+		   alg);
+	return 0;
+}
+
+
+static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP_256:
+		return WLAN_CIPHER_SUITE_CCMP_256;
+	case WPA_CIPHER_GCMP_256:
+		return WLAN_CIPHER_SUITE_GCMP_256;
+	case WPA_CIPHER_CCMP:
+		return WLAN_CIPHER_SUITE_CCMP;
+	case WPA_CIPHER_GCMP:
+		return WLAN_CIPHER_SUITE_GCMP;
+	case WPA_CIPHER_TKIP:
+		return WLAN_CIPHER_SUITE_TKIP;
+	case WPA_CIPHER_WEP104:
+		return WLAN_CIPHER_SUITE_WEP104;
+	case WPA_CIPHER_WEP40:
+		return WLAN_CIPHER_SUITE_WEP40;
+	}
+
+	return 0;
+}
+
+
+static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
+				       int max_suites)
+{
+	int num_suites = 0;
+
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+	if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+
+	return num_suites;
+}
+
+
 static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
@@ -4934,45 +5578,8 @@
 	} else {
 		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
 		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
-		switch (alg) {
-		case WPA_ALG_WEP:
-			if (key_len == 5)
-				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-					    WLAN_CIPHER_SUITE_WEP40);
-			else
-				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-					    WLAN_CIPHER_SUITE_WEP104);
-			break;
-		case WPA_ALG_TKIP:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_TKIP);
-			break;
-		case WPA_ALG_CCMP:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_CCMP);
-			break;
-		case WPA_ALG_GCMP:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_GCMP);
-			break;
-		case WPA_ALG_IGTK:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_AES_CMAC);
-			break;
-		case WPA_ALG_SMS4:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_SMS4);
-			break;
-		case WPA_ALG_KRK:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_KRK);
-			break;
-		default:
-			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
-				   "algorithm %d", __func__, alg);
-			nlmsg_free(msg);
-			return -1;
-		}
+		NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+			    wpa_alg_to_cipher_suite(alg, key_len));
 	}
 
 	if (seq && seq_len)
@@ -5077,33 +5684,8 @@
 
 	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
 
-	switch (alg) {
-	case WPA_ALG_WEP:
-		if (key_len == 5)
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP40);
-		else
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP104);
-		break;
-	case WPA_ALG_TKIP:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
-		break;
-	case WPA_ALG_CCMP:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
-		break;
-	case WPA_ALG_GCMP:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
-		break;
-	case WPA_ALG_IGTK:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-			    WLAN_CIPHER_SUITE_AES_CMAC);
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
-			   "algorithm %d", __func__, alg);
-		return -1;
-	}
+	NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+		    wpa_alg_to_cipher_suite(alg, key_len));
 
 	if (seq && seq_len)
 		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
@@ -5475,7 +6057,7 @@
 	struct wpa_driver_nl80211_data *drv)
 {
 	struct wpa_driver_auth_params params;
-	struct i802_bss *bss = &drv->first_bss;
+	struct i802_bss *bss = drv->first_bss;
 	int i;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
@@ -5565,17 +6147,11 @@
 
 	if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
 		chan->flag |= HOSTAPD_CHAN_DISABLED;
-	if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
-		chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
-	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
-		chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+		chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS;
 	if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
 		chan->flag |= HOSTAPD_CHAN_RADAR;
 
-	if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
-	    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-		chan->max_tx_power = nla_get_u32(
-			tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
 	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
 		enum nl80211_dfs_state state =
 			nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -5601,8 +6177,7 @@
 	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
 		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
 		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
 		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
 		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
 		[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
@@ -5898,25 +6473,29 @@
 }
 
 
-static void nl80211_reg_rule_ht40(struct nlattr *tb[],
-				  struct phy_info_arg *results)
+static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
+				      struct phy_info_arg *results)
 {
-	u32 start, end, max_bw;
 	u16 m;
 
-	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
-		return;
+	for (m = 0; m < *results->num_modes; m++) {
+		int c;
+		struct hostapd_hw_modes *mode = &results->modes[m];
 
-	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
-	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
-	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+			if ((u32) chan->freq - 10 >= start &&
+			    (u32) chan->freq + 10 <= end)
+				chan->max_tx_power = max_eirp;
+		}
+	}
+}
 
-	wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
-		   start, end, max_bw);
-	if (max_bw < 40)
-		return;
+
+static void nl80211_reg_rule_ht40(u32 start, u32 end,
+				  struct phy_info_arg *results)
+{
+	u16 m;
 
 	for (m = 0; m < *results->num_modes; m++) {
 		if (!(results->modes[m].ht_capab &
@@ -5954,6 +6533,76 @@
 }
 
 
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+				 int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+		if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+		if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+		if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+	}
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+				 struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	if (max_bw < 80)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		/* TODO: use a real VHT support indication */
+		if (!results->modes[m].vht_capab)
+			continue;
+
+		nl80211_set_vht_mode(&results->modes[m], start, end);
+	}
+}
+
+
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+	switch (region) {
+	case NL80211_DFS_UNSET:
+		return "DFS-UNSET";
+	case NL80211_DFS_FCC:
+		return "DFS-FCC";
+	case NL80211_DFS_ETSI:
+		return "DFS-ETSI";
+	case NL80211_DFS_JP:
+		return "DFS-JP";
+	default:
+		return "DFS-invalid";
+	}
+}
+
+
 static int nl80211_get_reg(struct nl_msg *msg, void *arg)
 {
 	struct phy_info_arg *results = arg;
@@ -5980,14 +6629,39 @@
 		return NL_SKIP;
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
-		   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+	if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+		enum nl80211_dfs_regions dfs_domain;
+		dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+			   dfs_domain_name(dfs_domain));
+	} else {
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+	}
 
 	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
 	{
+		u32 start, end, max_eirp = 0, max_bw = 0;
 		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
 			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
-		nl80211_reg_rule_ht40(tb_rule, results);
+		if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+		    tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
+			continue;
+		start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+		end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+			max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+		if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+			max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+		wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm",
+			   start, end, max_bw, max_eirp);
+		if (max_bw >= 40)
+			nl80211_reg_rule_ht40(start, end, results);
+		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+			nl80211_reg_rule_max_eirp(start, end, max_eirp,
+						  results);
 	}
 
 	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
@@ -5997,12 +6671,19 @@
 		nl80211_reg_rule_sec(tb_rule, results);
 	}
 
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_vht(tb_rule, results);
+	}
+
 	return NL_SKIP;
 }
 
 
-static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
-				  struct phy_info_arg *results)
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+					struct phy_info_arg *results)
 {
 	struct nl_msg *msg;
 
@@ -6042,10 +6723,11 @@
 		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
 
 	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
-		nl80211_set_ht40_flags(drv, &result);
+		nl80211_set_regulatory_flags(drv, &result);
 		return wpa_driver_nl80211_postprocess_modes(result.modes,
 							    num_modes);
 	}
@@ -6121,16 +6803,42 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	u64 cookie;
+	int res;
 
-	if (freq == 0)
+	if (freq == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
+			   bss->freq);
 		freq = bss->freq;
+	}
 
-	if (drv->use_monitor)
+	if (drv->use_monitor) {
+		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+			   freq, bss->freq);
 		return wpa_driver_nl80211_send_mntr(drv, data, len,
 						    encrypt, noack);
+	}
 
-	return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
-				      &cookie, no_cck, noack, offchanok);
+	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
+	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+				     &cookie, no_cck, noack, offchanok);
+	if (res == 0 && !noack) {
+		const struct ieee80211_mgmt *mgmt;
+		u16 fc;
+
+		mgmt = (const struct ieee80211_mgmt *) data;
+		fc = le_to_host16(mgmt->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+			wpa_printf(MSG_MSGDUMP,
+				   "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
+				   (long long unsigned int)
+				   drv->send_action_cookie,
+				   (long long unsigned int) cookie);
+			drv->send_action_cookie = cookie;
+		}
+	}
+
+	return res;
 }
 
 
@@ -6147,6 +6855,8 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
+		   noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
 
 	if ((is_sta_interface(drv->nlmode) ||
 	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -6157,16 +6867,22 @@
 		 * but it works due to the single-threaded nature
 		 * of wpa_supplicant.
 		 */
-		if (freq == 0)
+		if (freq == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
+				   drv->last_mgmt_freq);
 			freq = drv->last_mgmt_freq;
+		}
 		return nl80211_send_frame_cmd(bss, freq, 0,
 					      data, data_len, NULL, 1, noack,
 					      1);
 	}
 
 	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
-		if (freq == 0)
+		if (freq == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
+				   bss->freq);
 			freq = bss->freq;
+		}
 		return nl80211_send_frame_cmd(bss, freq,
 					      (int) freq == bss->freq ? 0 :
 					      wait_time,
@@ -6189,6 +6905,7 @@
 			encrypt = 0;
 	}
 
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
 	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
 					     noack, freq, no_cck, offchanok,
 					     wait_time);
@@ -6305,7 +7022,7 @@
 	int beacon_set;
 	int ifindex = if_nametoindex(bss->ifname);
 	int num_suites;
-	u32 suites[10];
+	u32 suites[10], suite;
 	u32 ver;
 
 	beacon_set = bss->beacon_set;
@@ -6400,17 +7117,8 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
 		   params->pairwise_ciphers);
-	num_suites = 0;
-	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
-		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
-	if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
-		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
-	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
-		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
-	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
-		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
-	if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
-		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+	num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
+						 suites, ARRAY_SIZE(suites));
 	if (num_suites) {
 		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
 			num_suites * sizeof(u32), suites);
@@ -6418,28 +7126,9 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
 		   params->group_cipher);
-	switch (params->group_cipher) {
-	case WPA_CIPHER_CCMP:
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
-			    WLAN_CIPHER_SUITE_CCMP);
-		break;
-	case WPA_CIPHER_GCMP:
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
-			    WLAN_CIPHER_SUITE_GCMP);
-		break;
-	case WPA_CIPHER_TKIP:
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
-			    WLAN_CIPHER_SUITE_TKIP);
-		break;
-	case WPA_CIPHER_WEP104:
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
-			    WLAN_CIPHER_SUITE_WEP104);
-		break;
-	case WPA_CIPHER_WEP40:
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
-			    WLAN_CIPHER_SUITE_WEP40);
-		break;
-	}
+	suite = wpa_cipher_to_cipher_suite(params->group_cipher);
+	if (suite)
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite);
 
 	if (params->beacon_ies) {
 		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
@@ -6486,24 +7175,9 @@
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-				       struct hostapd_freq_params *freq)
+static int nl80211_put_freq_params(struct nl_msg *msg,
+				   struct hostapd_freq_params *freq)
 {
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
-		   " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
-		   freq->freq, freq->ht_enabled, freq->vht_enabled,
-		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
 	if (freq->vht_enabled) {
 		switch (freq->bandwidth) {
@@ -6528,7 +7202,7 @@
 				    NL80211_CHAN_WIDTH_160);
 			break;
 		default:
-			return -1;
+			return -EINVAL;
 		}
 		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
 		if (freq->center_freq2)
@@ -6550,6 +7224,33 @@
 			break;
 		}
 	}
+	return 0;
+
+nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+				       struct hostapd_freq_params *freq)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+		   freq->freq, freq->ht_enabled, freq->vht_enabled,
+		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_put_freq_params(msg, freq) < 0)
+		goto nla_put_failure;
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
@@ -6651,6 +7352,12 @@
 			params->vht_capabilities);
 	}
 
+	if (params->vht_opmode_enabled) {
+		wpa_printf(MSG_DEBUG, "  * opmode=%u", params->vht_opmode);
+		NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF,
+			   params->vht_opmode);
+	}
+
 	wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
 	NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
 
@@ -6661,6 +7368,22 @@
 			params->ext_capab_len, params->ext_capab);
 	}
 
+	if (params->supp_channels) {
+		wpa_hexdump(MSG_DEBUG, "  * supported channels",
+			    params->supp_channels, params->supp_channels_len);
+		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+			params->supp_channels_len, params->supp_channels);
+	}
+
+	if (params->supp_oper_classes) {
+		wpa_hexdump(MSG_DEBUG, "  * supported operating classes",
+			    params->supp_oper_classes,
+			    params->supp_oper_classes_len);
+		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+			params->supp_oper_classes_len,
+			params->supp_oper_classes);
+	}
+
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = sta_flags_nl80211(params->flags);
 	upd.set = upd.mask;
@@ -6800,7 +7523,7 @@
 		return -1;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -6856,7 +7579,7 @@
 				const char *ifname, enum nl80211_iftype iftype,
 				const u8 *addr, int wds,
 				int (*handler)(struct nl_msg *, void *),
-				void *arg)
+				void *arg, int use_existing)
 {
 	int ret;
 
@@ -6865,6 +7588,11 @@
 
 	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
+		if (use_existing) {
+			wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+				   ifname);
+			return -ENFILE;
+		}
 		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
 		/* Try to remove the interface that was already there. */
@@ -6966,12 +7694,13 @@
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+			   strerror(errno));
 		return;
 	}
 
 	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
-		printf("received invalid radiotap frame\n");
+		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
 		return;
 	}
 
@@ -6980,7 +7709,8 @@
 		if (ret == -ENOENT)
 			break;
 		if (ret) {
-			printf("received invalid radiotap frame (%d)\n", ret);
+			wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+				   ret);
 			return;
 		}
 		switch (iter.this_arg_index) {
@@ -7130,7 +7860,7 @@
 };
 
 static struct sock_fprog msock_filter = {
-	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+	.len = ARRAY_SIZE(msock_filter_insns),
 	.filter = msock_filter_insns,
 };
 
@@ -7165,7 +7895,8 @@
 
 	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
 		       &msock_filter, sizeof(msock_filter))) {
-		perror("SO_ATTACH_FILTER");
+		wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -7176,7 +7907,10 @@
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv)
 {
-	drv->monitor_refcount--;
+	if (drv->monitor_refcount > 0)
+		drv->monitor_refcount--;
+	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+		   drv->monitor_refcount);
 	if (drv->monitor_refcount > 0)
 		return;
 
@@ -7202,27 +7936,29 @@
 
 	if (drv->monitor_ifidx >= 0) {
 		drv->monitor_refcount++;
+		wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+			   drv->monitor_refcount);
 		return 0;
 	}
 
-	if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+	if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
 		/*
 		 * P2P interface name is of the format p2p-%s-%d. For monitor
 		 * interface name corresponding to P2P GO, replace "p2p-" with
 		 * "mon-" to retain the same interface name length and to
 		 * indicate that it is a monitor interface.
 		 */
-		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
 	} else {
 		/* Non-P2P interface with AP functionality. */
-		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
 	}
 
 	buf[IFNAMSIZ - 1] = '\0';
 
 	drv->monitor_ifidx =
 		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0, NULL, NULL);
+				     0, NULL, NULL, 0);
 
 	if (drv->monitor_ifidx == -EOPNOTSUPP) {
 		/*
@@ -7247,7 +7983,8 @@
 	ll.sll_ifindex = drv->monitor_ifidx;
 	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (drv->monitor_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+			   strerror(errno));
 		goto error;
 	}
 
@@ -7258,7 +7995,8 @@
 	}
 
 	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("monitor socket bind");
+		wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+			   strerror(errno));
 		goto error;
 	}
 
@@ -7266,16 +8004,18 @@
 	optval = 20;
 	if (setsockopt
 	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
-		perror("Failed to set socket priority");
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+			   strerror(errno));
 		goto error;
 	}
 
 	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
 				     drv, NULL)) {
-		printf("Could not register monitor read socket\n");
+		wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
 		goto error;
 	}
 
+	drv->monitor_refcount++;
 	return 0;
  error:
 	nl80211_remove_monitor_interface(drv);
@@ -7287,8 +8027,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
-		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+	wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
 
 	/*
 	 * Disable Probe Request reporting unless we need it in this way for
@@ -7311,16 +8051,6 @@
 	    !drv->device_ap_sme)
 		return -1;
 
-#ifdef ANDROID_P2P
-	if (drv->device_ap_sme && drv->use_monitor)
-		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
-			return -1;
-
-	if (drv->use_monitor &&
-	    nl80211_create_monitor_interface(drv))
-		return -1;
-#endif
-
 	if (drv->device_ap_sme &&
 	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
@@ -7336,6 +8066,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
 	if (drv->device_ap_sme) {
 		wpa_driver_nl80211_probe_req_report(bss, 0);
 		if (!drv->use_monitor)
@@ -7390,19 +8122,16 @@
 	u8 *pos;
 	int res;
 	int qos = flags & WPA_STA_WMM;
-#ifndef ANDROID_P2P
+
 	if (drv->device_ap_sme || !drv->use_monitor)
-#else
-	if (drv->device_ap_sme && !drv->use_monitor)
-#endif
 		return nl80211_send_eapol_data(bss, addr, data, data_len);
 
 	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
 		data_len;
 	hdr = os_zalloc(len);
 	if (hdr == NULL) {
-		printf("malloc() failed for i802_send_data(len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+			   (unsigned long) len);
 		return -1;
 	}
 
@@ -7519,14 +8248,14 @@
 		nlmode = NL80211_IFTYPE_AP;
 
 	old_mode = drv->nlmode;
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+	if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
 
-	if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+	if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
 		if (old_mode != nlmode)
-			wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+			wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
@@ -7558,6 +8287,12 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
 
 nla_put_failure:
+	if (wpa_driver_nl80211_set_mode(drv->first_bss,
+					NL80211_IFTYPE_STATION)) {
+		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+			   "station mode");
+	}
+
 	nlmsg_free(msg);
 	return ret;
 }
@@ -7572,7 +8307,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+	if (wpa_driver_nl80211_set_mode(drv->first_bss,
 					NL80211_IFTYPE_ADHOC)) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
 			   "IBSS mode");
@@ -7610,10 +8345,10 @@
 		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
 	}
 
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK ||
-	    params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
+	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 ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
 		wpa_printf(MSG_DEBUG, "  * control port");
 		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
 	}
@@ -7651,40 +8386,45 @@
 }
 
 
-static int wpa_driver_nl80211_try_connect(
-	struct wpa_driver_nl80211_data *drv,
-	struct wpa_driver_associate_params *params)
+static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
+				  struct wpa_driver_associate_params *params,
+				  struct nl_msg *msg)
 {
-	struct nl_msg *msg;
-	enum nl80211_auth_type type;
-	int ret = 0;
-	int algs;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
-
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
 	if (params->bssid) {
 		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
 			   MAC2STR(params->bssid));
 		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
 	}
+
+	if (params->bssid_hint) {
+		wpa_printf(MSG_DEBUG, "  * bssid_hint=" MACSTR,
+			   MAC2STR(params->bssid_hint));
+		NLA_PUT(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
+			params->bssid_hint);
+	}
+
 	if (params->freq) {
 		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
 		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
 		drv->assoc_freq = params->freq;
 	} else
 		drv->assoc_freq = 0;
+
+	if (params->freq_hint) {
+		wpa_printf(MSG_DEBUG, "  * freq_hint=%d", params->freq_hint);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
+			    params->freq_hint);
+	}
+
 	if (params->bg_scan_period >= 0) {
 		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
 			   params->bg_scan_period);
 		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
 			    params->bg_scan_period);
 	}
+
 	if (params->ssid) {
 		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
 				  params->ssid, params->ssid_len);
@@ -7695,11 +8435,122 @@
 		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
 		drv->ssid_len = params->ssid_len;
 	}
+
 	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
 	if (params->wpa_ie)
 		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
 			params->wpa_ie);
 
+	if (params->wpa_proto) {
+		enum nl80211_wpa_versions ver = 0;
+
+		if (params->wpa_proto & WPA_PROTO_WPA)
+			ver |= NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_RSN)
+			ver |= NL80211_WPA_VERSION_2;
+
+		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
+		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+	}
+
+	if (params->pairwise_suite != WPA_CIPHER_NONE) {
+		u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
+		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+	}
+
+	if (params->group_suite != WPA_CIPHER_NONE) {
+		u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
+		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+	}
+
+	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_CCKM) {
+		int mgmt = WLAN_AKM_SUITE_PSK;
+
+		switch (params->key_mgmt_suite) {
+		case WPA_KEY_MGMT_CCKM:
+			mgmt = WLAN_AKM_SUITE_CCKM;
+			break;
+		case WPA_KEY_MGMT_IEEE8021X:
+			mgmt = WLAN_AKM_SUITE_8021X;
+			break;
+		case WPA_KEY_MGMT_FT_IEEE8021X:
+			mgmt = WLAN_AKM_SUITE_FT_8021X;
+			break;
+		case WPA_KEY_MGMT_FT_PSK:
+			mgmt = WLAN_AKM_SUITE_FT_PSK;
+			break;
+		case WPA_KEY_MGMT_PSK:
+		default:
+			mgmt = WLAN_AKM_SUITE_PSK;
+			break;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+	}
+
+	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+
+	if (params->disable_ht)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+	if (params->htcaps && params->htcaps_mask) {
+		int sz = sizeof(struct ieee80211_ht_capabilities);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+			params->htcaps_mask);
+	}
+
+#ifdef CONFIG_VHT_OVERRIDES
+	if (params->disable_vht) {
+		wpa_printf(MSG_DEBUG, "  * VHT disabled");
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+	}
+
+	if (params->vhtcaps && params->vhtcaps_mask) {
+		int sz = sizeof(struct ieee80211_vht_capabilities);
+		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+			params->vhtcaps_mask);
+	}
+#endif /* CONFIG_VHT_OVERRIDES */
+
+	if (params->p2p)
+		wpa_printf(MSG_DEBUG, "  * P2P group");
+
+	return 0;
+nla_put_failure:
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_try_connect(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_driver_associate_params *params)
+{
+	struct nl_msg *msg;
+	enum nl80211_auth_type type;
+	int ret;
+	int algs;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
+
+	ret = nl80211_connect_common(drv, params, msg);
+	if (ret)
+		goto nla_put_failure;
+
 	algs = 0;
 	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
 		algs++;
@@ -7728,129 +8579,6 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
 
 skip_auth_type:
-	if (params->wpa_proto) {
-		enum nl80211_wpa_versions ver = 0;
-
-		if (params->wpa_proto & WPA_PROTO_WPA)
-			ver |= NL80211_WPA_VERSION_1;
-		if (params->wpa_proto & WPA_PROTO_RSN)
-			ver |= NL80211_WPA_VERSION_2;
-
-		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
-		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
-	}
-
-	if (params->pairwise_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->pairwise_suite) {
-		case CIPHER_SMS4:
-			cipher = WLAN_CIPHER_SUITE_SMS4;
-			break;
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_GCMP:
-			cipher = WLAN_CIPHER_SUITE_GCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
-	}
-
-	if (params->group_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->group_suite) {
-		case CIPHER_SMS4:
-			cipher = WLAN_CIPHER_SUITE_SMS4;
-			break;
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_GCMP:
-			cipher = WLAN_CIPHER_SUITE_GCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK ||
-	    params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
-	    params->key_mgmt_suite == KEY_MGMT_CCKM) {
-		int mgmt = WLAN_AKM_SUITE_PSK;
-
-		switch (params->key_mgmt_suite) {
-		case KEY_MGMT_CCKM:
-			mgmt = WLAN_AKM_SUITE_CCKM;
-			break;
-		case KEY_MGMT_802_1X:
-			mgmt = WLAN_AKM_SUITE_8021X;
-			break;
-		case KEY_MGMT_FT_802_1X:
-			mgmt = WLAN_AKM_SUITE_FT_8021X;
-			break;
-		case KEY_MGMT_FT_PSK:
-			mgmt = WLAN_AKM_SUITE_FT_PSK;
-			break;
-		case KEY_MGMT_PSK:
-		default:
-			mgmt = WLAN_AKM_SUITE_PSK;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
-		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
-#endif /* CONFIG_IEEE80211W */
-
-	if (params->disable_ht)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
-
-	if (params->htcaps && params->htcaps_mask) {
-		int sz = sizeof(struct ieee80211_ht_capabilities);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-			params->htcaps_mask);
-	}
-
-#ifdef CONFIG_VHT_OVERRIDES
-	if (params->disable_vht) {
-		wpa_printf(MSG_DEBUG, "  * VHT disabled");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
-	}
-
-	if (params->vhtcaps && params->vhtcaps_mask) {
-		int sz = sizeof(struct ieee80211_vht_capabilities);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-			params->vhtcaps_mask);
-	}
-#endif /* CONFIG_VHT_OVERRIDES */
-
 	ret = nl80211_set_conn_keys(params, msg);
 	if (ret)
 		goto nla_put_failure;
@@ -7900,7 +8628,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1;
+	int ret;
 	struct nl_msg *msg;
 
 	if (params->mode == IEEE80211_MODE_AP)
@@ -7928,95 +8656,9 @@
 		   drv->ifindex);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
-	}
-	if (params->freq) {
-		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-		drv->assoc_freq = params->freq;
-	} else
-		drv->assoc_freq = 0;
-	if (params->bg_scan_period >= 0) {
-		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
-			   params->bg_scan_period);
-		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
-			    params->bg_scan_period);
-	}
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
-		if (params->ssid_len > sizeof(drv->ssid))
-			goto nla_put_failure;
-		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
-		drv->ssid_len = params->ssid_len;
-	}
-	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
-	if (params->wpa_ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
-
-	if (params->pairwise_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->pairwise_suite) {
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_GCMP:
-			cipher = WLAN_CIPHER_SUITE_GCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
-	}
-
-	if (params->group_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->group_suite) {
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_GCMP:
-			cipher = WLAN_CIPHER_SUITE_GCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
-		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
-#endif /* CONFIG_IEEE80211W */
-
-	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+	ret = nl80211_connect_common(drv, params, msg);
+	if (ret)
+		goto nla_put_failure;
 
 	if (params->prev_bssid) {
 		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
@@ -8025,33 +8667,6 @@
 			params->prev_bssid);
 	}
 
-	if (params->disable_ht)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
-
-	if (params->htcaps && params->htcaps_mask) {
-		int sz = sizeof(struct ieee80211_ht_capabilities);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-			params->htcaps_mask);
-	}
-
-#ifdef CONFIG_VHT_OVERRIDES
-	if (params->disable_vht) {
-		wpa_printf(MSG_DEBUG, "  * VHT disabled");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
-	}
-
-	if (params->vhtcaps && params->vhtcaps_mask) {
-		int sz = sizeof(struct ieee80211_vht_capabilities);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-			params->vhtcaps_mask);
-	}
-#endif /* CONFIG_VHT_OVERRIDES */
-
-	if (params->p2p)
-		wpa_printf(MSG_DEBUG, "  * P2P group");
-
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
@@ -8085,7 +8700,7 @@
 		return -ENOMEM;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
 		goto nla_put_failure;
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
@@ -8226,8 +8841,9 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
-	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
-		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+	wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
+		   bss->ifname, drv->operstate, state,
+		   state ? "UP" : "DORMANT");
 	drv->operstate = state;
 	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
 				      state ? IF_OPER_UP : IF_OPER_DORMANT);
@@ -8240,6 +8856,12 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
+	int ret = -ENOBUFS;
+
+	if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
+		wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
+		return 0;
+	}
 
 	wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
 		   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
@@ -8260,10 +8882,15 @@
 		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (!ret)
+		return 0;
  nla_put_failure:
 	nlmsg_free(msg);
-	return -ENOBUFS;
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
+		   ret, strerror(-ret));
+	return ret;
 }
 
 
@@ -8275,8 +8902,6 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static inline int min_int(int a, int b)
 {
 	if (a < b)
@@ -8431,8 +9056,6 @@
 	return -ENOBUFS;
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
 
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
@@ -8513,8 +9136,6 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 				    int cw_min, int cw_max, int burst_time)
 {
@@ -8585,6 +9206,10 @@
 	if (!msg)
 		return -ENOMEM;
 
+	wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+		   ", ifname=%s[%d], vlan_id=%d)",
+		   bss->ifname, if_nametoindex(bss->ifname),
+		   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -8676,9 +9301,6 @@
 					    0);
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
@@ -8760,7 +9382,8 @@
 		if (!if_nametoindex(name)) {
 			if (nl80211_create_iface(drv, name,
 						 NL80211_IFTYPE_AP_VLAN,
-						 bss->addr, 1, NULL, NULL) < 0)
+						 bss->addr, 1, NULL, NULL, 0) <
+			    0)
 				return -1;
 			if (bridge_ifname &&
 			    linux_br_add_if(drv->global->ioctl_sock,
@@ -8795,7 +9418,8 @@
 	len = recvfrom(sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *)&lladdr, &fromlen);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -8868,14 +9492,13 @@
 	int ifindex, br_ifindex;
 	int br_added = 0;
 
-	bss = wpa_driver_nl80211_init(hapd, params->ifname,
-				      params->global_priv);
+	bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+					  params->global_priv, 1,
+					  params->bssid);
 	if (bss == NULL)
 		return NULL;
 
 	drv = bss->drv;
-	drv->nlmode = NL80211_IFTYPE_AP;
-	drv->eapol_sock = -1;
 
 	if (linux_br_get(brname, params->ifname) == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
@@ -8886,8 +9509,6 @@
 		br_ifindex = 0;
 	}
 
-	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
-	drv->if_indices = drv->default_if_indices;
 	for (i = 0; i < params->num_bridge; i++) {
 		if (params->bridge[i]) {
 			ifindex = if_nametoindex(params->bridge[i]);
@@ -8904,37 +9525,20 @@
 	/* start listening for EAPOL on the default AP interface */
 	add_ifidx(drv, drv->ifindex);
 
-	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
-		goto failed;
-
-	if (params->bssid) {
-		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-				       params->bssid))
-			goto failed;
-	}
-
-	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-			   "into AP mode", bss->ifname);
-		goto failed;
-	}
-
 	if (params->num_bridge && params->bridge[0] &&
 	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
 		goto failed;
 
-	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
-		goto failed;
-
 	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
 	if (drv->eapol_sock < 0) {
-		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+		wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+			   strerror(errno));
 		goto failed;
 	}
 
 	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
 	{
-		printf("Could not register read socket for eapol\n");
+		wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
 		goto failed;
 	}
 
@@ -8958,8 +9562,6 @@
 	wpa_driver_nl80211_deinit(bss);
 }
 
-#endif /* HOSTAPD */
-
 
 static enum nl80211_iftype wpa_driver_nl80211_if_type(
 	enum wpa_driver_if_type type)
@@ -8990,7 +9592,7 @@
 	struct wpa_driver_nl80211_data *drv;
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
-		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+		if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
 			return 1;
 	}
 	return 0;
@@ -9005,9 +9607,9 @@
 	if (!drv->global)
 		return -1;
 
-	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+	os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
 	for (idx = 0; idx < 64; idx++) {
-		new_addr[0] = drv->first_bss.addr[0] | 0x02;
+		new_addr[0] = drv->first_bss->addr[0] | 0x02;
 		new_addr[0] ^= idx << 2;
 		if (!nl80211_addr_in_use(drv->global, new_addr))
 			break;
@@ -9055,21 +9657,13 @@
 				     const char *ifname, const u8 *addr,
 				     void *bss_ctx, void **drv_priv,
 				     char *force_ifname, u8 *if_addr,
-				     const char *bridge)
+				     const char *bridge, int use_existing)
 {
 	enum nl80211_iftype nlmode;
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifidx;
-#ifdef HOSTAPD
-	struct i802_bss *new_bss = NULL;
-
-	if (type == WPA_IF_AP_BSS) {
-		new_bss = os_zalloc(sizeof(*new_bss));
-		if (new_bss == NULL)
-			return -1;
-	}
-#endif /* HOSTAPD */
+	int added = 1;
 
 	if (addr)
 		os_memcpy(if_addr, addr, ETH_ALEN);
@@ -9080,7 +9674,7 @@
 		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
 		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
 					     0, nl80211_wdev_handler,
-					     &p2pdev_info);
+					     &p2pdev_info, use_existing);
 		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
 				   ifname);
@@ -9096,11 +9690,11 @@
 			   (long long unsigned int) p2pdev_info.wdev_id);
 	} else {
 		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
-					     0, NULL, NULL);
-		if (ifidx < 0) {
-#ifdef HOSTAPD
-			os_free(new_bss);
-#endif /* HOSTAPD */
+					     0, NULL, NULL, use_existing);
+		if (use_existing && ifidx == -ENFILE) {
+			added = 0;
+			ifidx = if_nametoindex(ifname);
+		} else if (ifidx < 0) {
 			return -1;
 		}
 	}
@@ -9110,7 +9704,8 @@
 			os_memcpy(if_addr, bss->addr, ETH_ALEN);
 		else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
 					    bss->ifname, if_addr) < 0) {
-			nl80211_remove_iface(drv, ifidx);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
 	}
@@ -9144,17 +9739,25 @@
 	}
 #endif /* CONFIG_P2P */
 
-#ifdef HOSTAPD
-	if (bridge &&
-	    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
-			   "interface %s to a bridge %s", ifname, bridge);
-		nl80211_remove_iface(drv, ifidx);
-		os_free(new_bss);
-		return -1;
-	}
-
 	if (type == WPA_IF_AP_BSS) {
+		struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+		if (new_bss == NULL) {
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
+			return -1;
+		}
+
+		if (bridge &&
+		    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+				   "interface %s to a bridge %s",
+				   ifname, bridge);
+			if (added)
+				nl80211_remove_iface(drv, ifidx);
+			os_free(new_bss);
+			return -1;
+		}
+
 		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
 		{
 			nl80211_remove_iface(drv, ifidx);
@@ -9165,10 +9768,11 @@
 		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
 		new_bss->ifindex = ifidx;
 		new_bss->drv = drv;
-		new_bss->next = drv->first_bss.next;
-		new_bss->freq = drv->first_bss.freq;
+		new_bss->next = drv->first_bss->next;
+		new_bss->freq = drv->first_bss->freq;
 		new_bss->ctx = bss_ctx;
-		drv->first_bss.next = new_bss;
+		new_bss->added_if = added;
+		drv->first_bss->next = new_bss;
 		if (drv_priv)
 			*drv_priv = new_bss;
 		nl80211_init_bss(new_bss);
@@ -9177,7 +9781,6 @@
 		if (nl80211_setup_ap(new_bss))
 			return -1;
 	}
-#endif /* HOSTAPD */
 
 	if (drv->global)
 		drv->global->if_add_ifindex = ifidx;
@@ -9193,14 +9796,11 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex = if_nametoindex(ifname);
 
-	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
-		   __func__, type, ifname, ifindex);
-	if (ifindex <= 0)
-		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+		   __func__, type, ifname, ifindex, bss->added_if);
+	if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
+		nl80211_remove_iface(drv, ifindex);
 
-	nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
 	if (type != WPA_IF_AP_BSS)
 		return 0;
 
@@ -9218,10 +9818,11 @@
 				   bss->brname, strerror(errno));
 	}
 
-	if (bss != &drv->first_bss) {
+	if (bss != drv->first_bss) {
 		struct i802_bss *tbss;
 
-		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+		wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+		for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
 			if (tbss->next == bss) {
 				tbss->next = bss->next;
 				/* Unsubscribe management frames */
@@ -9235,8 +9836,22 @@
 		if (bss)
 			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
 				   "BSS %p in the list", __func__, bss);
+	} else {
+		wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+		nl80211_teardown_ap(bss);
+		if (!bss->added_if && !drv->first_bss->next)
+			wpa_driver_nl80211_del_beacon(drv);
+		nl80211_destroy_bss(bss);
+		if (!bss->added_if)
+			i802_set_iface_flags(bss, 0);
+		if (drv->first_bss->next) {
+			drv->first_bss = drv->first_bss->next;
+			drv->ctx = drv->first_bss->ctx;
+			os_free(bss);
+		} else {
+			wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+		}
 	}
-#endif /* HOSTAPD */
 
 	return 0;
 }
@@ -9341,7 +9956,10 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	if (is_ap_interface(drv->nlmode))
+	if (is_ap_interface(drv->nlmode) &&
+	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+	     (int) freq == bss->freq || drv->device_ap_sme ||
+	     !drv->use_monitor))
 		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
 						   0, freq, no_cck, 1,
 						   wait_time);
@@ -9484,9 +10102,7 @@
 		} else if (bss->nl_preq) {
 			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
 				   "reporting nl_preq=%p", bss->nl_preq);
-			eloop_unregister_read_sock(
-				nl_socket_get_fd(bss->nl_preq));
-			nl_destroy_handles(&bss->nl_preq);
+			nl80211_destroy_eloop_handle(&bss->nl_preq);
 		}
 		return 0;
 	}
@@ -9509,9 +10125,9 @@
 				   NULL, 0) < 0)
 		goto out_err;
 
-	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
-				 wpa_driver_nl80211_event_receive, bss->nl_cb,
-				 bss->nl_preq);
+	nl80211_register_eloop_read(&bss->nl_preq,
+				    wpa_driver_nl80211_event_receive,
+				    bss->nl_cb);
 
 	return 0;
 
@@ -9712,27 +10328,6 @@
 }
 
 
-/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
-{
-	switch (width) {
-	case NL80211_CHAN_WIDTH_20_NOHT:
-		return CHAN_WIDTH_20_NOHT;
-	case NL80211_CHAN_WIDTH_20:
-		return CHAN_WIDTH_20;
-	case NL80211_CHAN_WIDTH_40:
-		return CHAN_WIDTH_40;
-	case NL80211_CHAN_WIDTH_80:
-		return CHAN_WIDTH_80;
-	case NL80211_CHAN_WIDTH_80P80:
-		return CHAN_WIDTH_80P80;
-	case NL80211_CHAN_WIDTH_160:
-		return CHAN_WIDTH_160;
-	}
-	return CHAN_WIDTH_UNKNOWN;
-}
-
-
 static int get_channel_width(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -9818,19 +10413,15 @@
 			 struct wpa_driver_nl80211_data, list) {
 		if (drv == driver ||
 		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
-#ifdef ANDROID_P2P
-		    (!driver->associated && !is_ap_interface(driver->nlmode)))
-#else
 		    !driver->associated)
-#endif
 			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));
+			   driver->phyname, driver->first_bss->ifname,
+			   MAC2STR(driver->first_bss->addr));
 		if (is_ap_interface(driver->nlmode))
-			freq = driver->first_bss.freq;
+			freq = driver->first_bss->freq;
 		else
 			freq = nl80211_get_assoc_freq(driver);
 		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
@@ -9876,17 +10467,19 @@
 		struct wpa_driver_nl80211_data *drv = bss->drv;
 		drv->allow_p2p_device = 1;
 	}
+#endif /* CONFIG_P2P */
 
-#ifdef ANDROID_P2P
-	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
+	if (os_strstr(param, "use_monitor=1")) {
 		struct i802_bss *bss = priv;
 		struct wpa_driver_nl80211_data *drv = bss->drv;
-		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
-			   "concurrency");
-		drv->capa.num_multichan_concurrent = 2;
+		drv->use_monitor = 1;
 	}
-#endif
-#endif /* CONFIG_P2P */
+
+	if (os_strstr(param, "force_connect_cmd=1")) {
+		struct i802_bss *bss = priv;
+		struct wpa_driver_nl80211_data *drv = bss->drv;
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
+	}
 
 	return 0;
 }
@@ -9922,7 +10515,8 @@
 
 	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (global->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
+		wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+			   strerror(errno));
 		goto err;
 	}
 
@@ -9950,11 +10544,8 @@
 
 	nl_destroy_handles(&global->nl);
 
-	if (global->nl_event) {
-		eloop_unregister_read_sock(
-			nl_socket_get_fd(global->nl_event));
-		nl_destroy_handles(&global->nl_event);
-	}
+	if (global->nl_event)
+		nl80211_destroy_eloop_handle(&global->nl_event);
 
 	nl_cb_put(global->nl_cb);
 
@@ -10122,6 +10713,9 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	if (!tb[NL80211_ATTR_IFINDEX])
+		return NL_SKIP;
+
 	ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
 	if (!tb[NL80211_ATTR_SURVEY_INFO])
@@ -10328,12 +10922,13 @@
 	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
 		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
 
-	if (opp_ps != -1 || ctwindow != -1)
+	if (opp_ps != -1 || ctwindow != -1) {
 #ifdef ANDROID_P2P
 		wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
-#else
+#else /* ANDROID_P2P */
 		return -1; /* Not yet supported */
-#endif
+#endif /* ANDROID_P2P */
+	}
 
 	if (legacy_ps == -1)
 		return 0;
@@ -10344,14 +10939,18 @@
 }
 
 
-static int nl80211_start_radar_detection(void *priv, int freq)
+static int nl80211_start_radar_detection(void *priv,
+					 struct hostapd_freq_params *freq)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+		   freq->freq, freq->ht_enabled, freq->vht_enabled,
+		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
+
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
 			   "detection");
@@ -10364,10 +10963,53 @@
 
 	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
 
-	/* only HT20 is supported at this point */
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+	if (freq->vht_enabled) {
+		switch (freq->bandwidth) {
+		case 20:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_20);
+			break;
+		case 40:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_40);
+			break;
+		case 80:
+			if (freq->center_freq2)
+				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+					    NL80211_CHAN_WIDTH_80P80);
+			else
+				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+					    NL80211_CHAN_WIDTH_80);
+			break;
+		case 160:
+			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+				    NL80211_CHAN_WIDTH_160);
+			break;
+		default:
+			return -1;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
+		if (freq->center_freq2)
+			NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
+				    freq->center_freq2);
+	} else if (freq->ht_enabled) {
+		switch (freq->sec_channel_offset) {
+		case -1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40MINUS);
+			break;
+		case 1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40PLUS);
+			break;
+		default:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT20);
+			break;
+		}
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret == 0)
@@ -10570,7 +11212,7 @@
 
 	memset(&ifr, 0, sizeof(ifr));
 	memset(&priv_cmd, 0, sizeof(priv_cmd));
-	os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
 
 	priv_cmd.buf = buf;
 	priv_cmd.used_len = bp;
@@ -10667,14 +11309,12 @@
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
 				       const char *ifname, int vlan_id)
 {
 	struct i802_bss *bss = priv;
 	return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
 }
-#endif /* HOSTAPD || CONFIG_AP */
 
 
 static int driver_nl80211_read_sta_data(void *priv,
@@ -10751,6 +11391,318 @@
 }
 
 
+static const char * scan_state_str(enum scan_states scan_state)
+{
+	switch (scan_state) {
+	case NO_SCAN:
+		return "NO_SCAN";
+	case SCAN_REQUESTED:
+		return "SCAN_REQUESTED";
+	case SCAN_STARTED:
+		return "SCAN_STARTED";
+	case SCAN_COMPLETED:
+		return "SCAN_COMPLETED";
+	case SCAN_ABORTED:
+		return "SCAN_ABORTED";
+	case SCHED_SCAN_STARTED:
+		return "SCHED_SCAN_STARTED";
+	case SCHED_SCAN_STOPPED:
+		return "SCHED_SCAN_STOPPED";
+	case SCHED_SCAN_RESULTS:
+		return "SCHED_SCAN_RESULTS";
+	}
+
+	return "??";
+}
+
+
+static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int res;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos,
+			  "ifindex=%d\n"
+			  "ifname=%s\n"
+			  "brname=%s\n"
+			  "addr=" MACSTR "\n"
+			  "freq=%d\n"
+			  "%s%s%s%s%s",
+			  bss->ifindex,
+			  bss->ifname,
+			  bss->brname,
+			  MAC2STR(bss->addr),
+			  bss->freq,
+			  bss->beacon_set ? "beacon_set=1\n" : "",
+			  bss->added_if_into_bridge ?
+			  "added_if_into_bridge=1\n" : "",
+			  bss->added_bridge ? "added_bridge=1\n" : "",
+			  bss->in_deinit ? "in_deinit=1\n" : "",
+			  bss->if_dynamic ? "if_dynamic=1\n" : "");
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	if (bss->wdev_id_set) {
+		res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
+				  (unsigned long long) bss->wdev_id);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	res = os_snprintf(pos, end - pos,
+			  "phyname=%s\n"
+			  "drv_ifindex=%d\n"
+			  "operstate=%d\n"
+			  "scan_state=%s\n"
+			  "auth_bssid=" MACSTR "\n"
+			  "auth_attempt_bssid=" MACSTR "\n"
+			  "bssid=" MACSTR "\n"
+			  "prev_bssid=" MACSTR "\n"
+			  "associated=%d\n"
+			  "assoc_freq=%u\n"
+			  "monitor_sock=%d\n"
+			  "monitor_ifidx=%d\n"
+			  "monitor_refcount=%d\n"
+			  "last_mgmt_freq=%u\n"
+			  "eapol_tx_sock=%d\n"
+			  "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+			  drv->phyname,
+			  drv->ifindex,
+			  drv->operstate,
+			  scan_state_str(drv->scan_state),
+			  MAC2STR(drv->auth_bssid),
+			  MAC2STR(drv->auth_attempt_bssid),
+			  MAC2STR(drv->bssid),
+			  MAC2STR(drv->prev_bssid),
+			  drv->associated,
+			  drv->assoc_freq,
+			  drv->monitor_sock,
+			  drv->monitor_ifidx,
+			  drv->monitor_refcount,
+			  drv->last_mgmt_freq,
+			  drv->eapol_tx_sock,
+			  drv->ignore_if_down_event ?
+			  "ignore_if_down_event=1\n" : "",
+			  drv->scan_complete_events ?
+			  "scan_complete_events=1\n" : "",
+			  drv->disabled_11b_rates ?
+			  "disabled_11b_rates=1\n" : "",
+			  drv->pending_remain_on_chan ?
+			  "pending_remain_on_chan=1\n" : "",
+			  drv->in_interface_list ? "in_interface_list=1\n" : "",
+			  drv->device_ap_sme ? "device_ap_sme=1\n" : "",
+			  drv->poll_command_supported ?
+			  "poll_command_supported=1\n" : "",
+			  drv->data_tx_status ? "data_tx_status=1\n" : "",
+			  drv->scan_for_auth ? "scan_for_auth=1\n" : "",
+			  drv->retry_auth ? "retry_auth=1\n" : "",
+			  drv->use_monitor ? "use_monitor=1\n" : "",
+			  drv->ignore_next_local_disconnect ?
+			  "ignore_next_local_disconnect=1\n" : "",
+			  drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	if (drv->has_capability) {
+		res = os_snprintf(pos, end - pos,
+				  "capa.key_mgmt=0x%x\n"
+				  "capa.enc=0x%x\n"
+				  "capa.auth=0x%x\n"
+				  "capa.flags=0x%x\n"
+				  "capa.max_scan_ssids=%d\n"
+				  "capa.max_sched_scan_ssids=%d\n"
+				  "capa.sched_scan_supported=%d\n"
+				  "capa.max_match_sets=%d\n"
+				  "capa.max_remain_on_chan=%u\n"
+				  "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",
+				  drv->capa.key_mgmt,
+				  drv->capa.enc,
+				  drv->capa.auth,
+				  drv->capa.flags,
+				  drv->capa.max_scan_ssids,
+				  drv->capa.max_sched_scan_ssids,
+				  drv->capa.sched_scan_supported,
+				  drv->capa.max_match_sets,
+				  drv->capa.max_remain_on_chan,
+				  drv->capa.max_stations,
+				  drv->capa.probe_resp_offloads,
+				  drv->capa.max_acl_mac_addrs,
+				  drv->capa.num_multichan_concurrent);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	return pos - buf;
+}
+
+
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+	if (settings->head)
+		NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
+			settings->head_len, settings->head);
+
+	if (settings->tail)
+		NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
+			settings->tail_len, settings->tail);
+
+	if (settings->beacon_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE,
+			settings->beacon_ies_len, settings->beacon_ies);
+
+	if (settings->proberesp_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			settings->proberesp_ies_len, settings->proberesp_ies);
+
+	if (settings->assocresp_ies)
+		NLA_PUT(msg,
+			NL80211_ATTR_IE_ASSOC_RESP,
+			settings->assocresp_ies_len, settings->assocresp_ies);
+
+	if (settings->probe_resp)
+		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
+			settings->probe_resp_len, settings->probe_resp);
+
+	return 0;
+
+nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+	struct nl_msg *msg;
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *beacon_csa;
+	int ret = -ENOBUFS;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
+		   settings->cs_count, settings->block_tx,
+		   settings->freq_params.freq, settings->freq_params.bandwidth,
+		   settings->freq_params.center_freq1,
+		   settings->freq_params.center_freq2);
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+		return -EOPNOTSUPP;
+	}
+
+	if ((drv->nlmode != NL80211_IFTYPE_AP) &&
+	    (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+		return -EOPNOTSUPP;
+
+	/* check settings validity */
+	if (!settings->beacon_csa.tail ||
+	    ((settings->beacon_csa.tail_len <=
+	      settings->counter_offset_beacon) ||
+	     (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
+	      settings->cs_count)))
+		return -EINVAL;
+
+	if (settings->beacon_csa.probe_resp &&
+	    ((settings->beacon_csa.probe_resp_len <=
+	      settings->counter_offset_presp) ||
+	     (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
+	      settings->cs_count)))
+		return -EINVAL;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
+	ret = nl80211_put_freq_params(msg, &settings->freq_params);
+	if (ret)
+		goto error;
+
+	if (settings->block_tx)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+	/* beacon_after params */
+	ret = set_beacon_data(msg, &settings->beacon_after);
+	if (ret)
+		goto error;
+
+	/* beacon_csa params */
+	beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+	if (!beacon_csa)
+		goto nla_put_failure;
+
+	ret = set_beacon_data(msg, &settings->beacon_csa);
+	if (ret)
+		goto error;
+
+	NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+		    settings->counter_offset_beacon);
+
+	if (settings->beacon_csa.probe_resp)
+		NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+			    settings->counter_offset_presp);
+
+	nla_nest_end(msg, beacon_csa);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+			   ret, strerror(-ret));
+	}
+	return ret;
+
+nla_put_failure:
+	ret = -ENOBUFS;
+error:
+	nlmsg_free(msg);
+	wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+	return ret;
+}
+
+
+static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
+			       u8 qos_map_set_len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+		    qos_map_set, qos_map_set_len);
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
+
+	return ret;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -10772,6 +11724,7 @@
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
+	.get_country = wpa_driver_nl80211_get_country,
 	.set_ap = wpa_driver_nl80211_set_ap,
 	.set_acl = wpa_driver_nl80211_set_acl,
 	.if_add = wpa_driver_nl80211_if_add,
@@ -10782,12 +11735,9 @@
 	.sta_remove = driver_nl80211_sta_remove,
 	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
 	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
-#ifdef HOSTAPD
 	.hapd_init = i802_init,
 	.hapd_deinit = i802_deinit,
 	.set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 	.get_seqnum = i802_get_seqnum,
 	.flush = i802_flush,
 	.get_inact_sec = i802_get_inact_sec,
@@ -10798,7 +11748,6 @@
 	.set_sta_vlan = driver_nl80211_set_sta_vlan,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
-#endif /* HOSTAPD || CONFIG_AP */
 	.read_sta_data = driver_nl80211_read_sta_data,
 	.set_freq = i802_set_freq,
 	.send_action = driver_nl80211_send_action,
@@ -10832,12 +11781,15 @@
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
 	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
 	.get_survey = wpa_driver_nl80211_get_survey,
+	.status = wpa_driver_nl80211_status,
+	.switch_channel = nl80211_switch_channel,
 #ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
 	.get_noa = wpa_driver_get_p2p_noa,
 	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
-#endif
+#endif /* ANDROID_P2P */
 #ifdef ANDROID
 	.driver_cmd = wpa_driver_nl80211_driver_cmd,
-#endif
+#endif /* ANDROID */
+	.set_qos_map = nl80211_set_qos_map,
 };
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 541ebcc..7d30655 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -28,7 +28,6 @@
 #include "common/ieee802_11_defs.h"
 #include "crypto/sha1.h"
 #include "l2_packet/l2_packet.h"
-#include "p2p/p2p.h"
 #include "wps/wps.h"
 #include "driver.h"
 
@@ -102,20 +101,6 @@
 	unsigned int remain_on_channel_duration;
 
 	int current_freq;
-
-	struct p2p_data *p2p;
-	unsigned int off_channel_freq;
-	struct wpabuf *pending_action_tx;
-	u8 pending_action_src[ETH_ALEN];
-	u8 pending_action_dst[ETH_ALEN];
-	u8 pending_action_bssid[ETH_ALEN];
-	unsigned int pending_action_freq;
-	unsigned int pending_action_no_cck;
-	unsigned int pending_listen_freq;
-	unsigned int pending_listen_duration;
-	int pending_p2p_scan;
-	struct sockaddr *probe_from;
-	socklen_t probe_from_len;
 };
 
 
@@ -125,7 +110,6 @@
 static void wpa_driver_test_close_test_socket(
 	struct wpa_driver_test_data *drv);
 static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
-static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv);
 
 
 static void test_driver_free_bss(struct test_driver_bss *bss)
@@ -479,34 +463,6 @@
 	event.tx_status.ack = ret >= 0;
 	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
 
-#ifdef CONFIG_P2P
-	if (drv->p2p &&
-	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
-		if (drv->pending_action_tx == NULL) {
-			wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
-				   "no pending operation");
-			return ret;
-		}
-
-		if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) !=
-		    0) {
-			wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
-				   "unknown destination address");
-			return ret;
-		}
-
-		wpabuf_free(drv->pending_action_tx);
-		drv->pending_action_tx = NULL;
-
-		p2p_send_action_cb(drv->p2p, drv->pending_action_freq,
-				   drv->pending_action_dst,
-				   drv->pending_action_src,
-				   drv->pending_action_bssid,
-				   ret >= 0);
-	}
-#endif /* CONFIG_P2P */
-
 	return ret;
 }
 
@@ -553,10 +509,6 @@
 		event.rx_probe_req.ie = ie;
 		event.rx_probe_req.ie_len = ielen;
 		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
-#ifdef CONFIG_P2P
-		if (drv->p2p)
-			p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
-#endif /* CONFIG_P2P */
 	}
 
 	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
@@ -1059,7 +1011,7 @@
 			      const char *ifname, const u8 *addr,
 			      void *bss_ctx, void **drv_priv,
 			      char *force_ifname, u8 *if_addr,
-			      const char *bridge)
+			      const char *bridge, int use_existing)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
@@ -1313,25 +1265,7 @@
 
 static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
-	struct wpa_driver_test_data *drv = eloop_ctx;
 	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	if (drv->pending_p2p_scan && drv->p2p) {
-#ifdef CONFIG_P2P
-		size_t i;
-		struct os_time now;
-		os_get_time(&now);
-		for (i = 0; i < drv->num_scanres; i++) {
-			struct wpa_scan_res *bss = drv->scanres[i];
-			if (p2p_scan_res_handler(drv->p2p, bss->bssid,
-						 bss->freq, &now, bss->level,
-						 (const u8 *) (bss + 1),
-						 bss->ie_len) > 0)
-				return;
-		}
-		p2p_scan_res_handled(drv->p2p);
-#endif /* CONFIG_P2P */
-		return;
-	}
 	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
 }
 
@@ -1949,30 +1883,8 @@
 				data_len - (mgmt->u.probe_req.variable - data);
 			wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
 					     &event);
-#ifdef CONFIG_P2P
-			if (drv->p2p)
-				p2p_probe_req_rx(drv->p2p, mgmt->sa,
-						 mgmt->da, mgmt->bssid,
-						 event.rx_probe_req.ie,
-						 event.rx_probe_req.ie_len);
-#endif /* CONFIG_P2P */
 		}
 	}
-
-#ifdef CONFIG_P2P
-	if (drv->p2p &&
-	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
-		size_t hdr_len;
-		hdr_len = (const u8 *)
-			&mgmt->u.action.u.vs_public_action.action - data;
-		p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
-			      mgmt->u.action.category,
-			      &mgmt->u.action.u.vs_public_action.action,
-			      data_len - hdr_len, freq);
-	}
-#endif /* CONFIG_P2P */
-
 }
 
 
@@ -1988,29 +1900,6 @@
 	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
 
 	/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
-#ifdef CONFIG_P2P
-	if (drv->probe_req_report && drv->p2p && data_len) {
-		const char *d = (const char *) data;
-		u8 sa[ETH_ALEN];
-		u8 ie[512];
-		size_t ielen;
-
-		if (hwaddr_aton(d, sa))
-			return;
-		d += 18;
-		while (*d == ' ')
-			d++;
-		ielen = os_strlen(d) / 2;
-		if (ielen > sizeof(ie))
-			ielen = sizeof(ie);
-		if (hexstr2bin(d, ie, ielen) < 0)
-			ielen = 0;
-		drv->probe_from = from;
-		drv->probe_from_len = fromlen;
-		p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
-		drv->probe_from = NULL;
-	}
-#endif /* CONFIG_P2P */
 
 	if (!drv->ibss)
 		return;
@@ -2167,12 +2056,6 @@
 	struct test_client_socket *cli, *prev;
 	int i;
 
-#ifdef CONFIG_P2P
-	if (drv->p2p)
-		p2p_deinit(drv->p2p);
-	wpabuf_free(drv->pending_action_tx);
-#endif /* CONFIG_P2P */
-
 	cli = drv->cli;
 	while (cli) {
 		prev = cli;
@@ -2369,13 +2252,6 @@
 		drv->use_associnfo = 1;
 	}
 
-	if (os_strstr(param, "p2p_mgmt=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
-			   "management");
-		if (wpa_driver_test_init_p2p(drv) < 0)
-			return -1;
-	}
-
 	return 0;
 }
 
@@ -2465,8 +2341,6 @@
 
 static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
 {
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
 	os_memset(capa, 0, sizeof(*capa));
 	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
@@ -2482,8 +2356,6 @@
 	capa->auth = WPA_DRIVER_AUTH_OPEN |
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
-	if (drv->p2p)
-		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
 	capa->flags |= WPA_DRIVER_FLAGS_AP;
 	capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 	capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
@@ -2691,33 +2563,6 @@
 }
 
 
-#ifdef CONFIG_P2P
-static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-
-	if (drv->pending_action_tx == NULL)
-		return;
-
-	if (drv->off_channel_freq != drv->pending_action_freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
-			   "waiting for another freq=%u",
-			   drv->pending_action_freq);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
-		   MACSTR, MAC2STR(drv->pending_action_dst));
-	wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
-				    drv->pending_action_dst,
-				    drv->pending_action_src,
-				    drv->pending_action_bssid,
-				    wpabuf_head(drv->pending_action_tx),
-				    wpabuf_len(drv->pending_action_tx),
-				    drv->pending_action_no_cck);
-}
-#endif /* CONFIG_P2P */
-
-
 static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_driver_test_data *drv = eloop_ctx;
@@ -2729,9 +2574,6 @@
 	data.remain_on_channel.freq = drv->remain_on_channel_freq;
 	data.remain_on_channel.duration = drv->remain_on_channel_duration;
 
-	if (drv->p2p)
-		drv->off_channel_freq = 0;
-
 	drv->remain_on_channel_freq = 0;
 
 	wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
@@ -2765,18 +2607,6 @@
 	data.remain_on_channel.duration = duration;
 	wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
 
-#ifdef CONFIG_P2P
-	if (drv->p2p) {
-		drv->off_channel_freq = drv->remain_on_channel_freq;
-		test_send_action_cb(drv, NULL);
-		if (drv->off_channel_freq == drv->pending_listen_freq) {
-			p2p_listen_cb(drv->p2p, drv->pending_listen_freq,
-				      drv->pending_listen_duration);
-			drv->pending_listen_freq = 0;
-		}
-	}
-#endif /* CONFIG_P2P */
-
 	return 0;
 }
 
@@ -2804,470 +2634,6 @@
 }
 
 
-#ifdef CONFIG_P2P
-
-static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
-	if (!drv->p2p)
-		return -1;
-	return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
-}
-
-
-static int wpa_driver_test_p2p_stop_find(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	if (!drv->p2p)
-		return -1;
-	p2p_stop_find(drv->p2p);
-	return 0;
-}
-
-
-static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
-	if (!drv->p2p)
-		return -1;
-	return p2p_listen(drv->p2p, timeout);
-}
-
-
-static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
-				       int wps_method, int go_intent,
-				       const u8 *own_interface_addr,
-				       unsigned int force_freq,
-				       int persistent_group)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
-		   "go_intent=%d "
-		   "own_interface_addr=" MACSTR " force_freq=%u "
-		   "persistent_group=%d)",
-		   __func__, MAC2STR(peer_addr), wps_method, go_intent,
-		   MAC2STR(own_interface_addr), force_freq, persistent_group);
-	if (!drv->p2p)
-		return -1;
-	return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
-			   own_interface_addr, force_freq, persistent_group,
-			   NULL, 0, 0, 0);
-}
-
-
-static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
-		   __func__, MAC2STR(peer_addr));
-	if (!drv->p2p)
-		return -1;
-	p2p_wps_success_cb(drv->p2p, peer_addr);
-	return 0;
-}
-
-
-static int wpa_driver_test_p2p_group_formation_failed(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	if (!drv->p2p)
-		return -1;
-	p2p_group_formation_failed(drv->p2p);
-	return 0;
-}
-
-
-static int wpa_driver_test_p2p_set_params(void *priv,
-					  const struct p2p_params *params)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	if (!drv->p2p)
-		return -1;
-	if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 ||
-	    p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 ||
-	    p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type,
-				  params->num_sec_dev_types) < 0)
-		return -1;
-	return 0;
-}
-
-
-static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
-			 unsigned int num_req_dev_types,
-			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
-{
-	struct wpa_driver_test_data *drv = ctx;
-	struct wpa_driver_scan_params params;
-	int ret;
-	struct wpabuf *wps_ie, *ies;
-	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
-	size_t ielen;
-
-	wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
-		   __func__, type, freq);
-
-	os_memset(&params, 0, sizeof(params));
-
-	/* P2P Wildcard SSID */
-	params.num_ssids = 1;
-	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
-	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
-
-#if 0 /* TODO: WPS IE */
-	wpa_s->wps->dev.p2p = 1;
-	wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
-					wpa_s->wps->uuid, WPS_REQ_ENROLLEE);
-#else
-	wps_ie = wpabuf_alloc(1);
-#endif
-	if (wps_ie == NULL)
-		return -1;
-
-	ielen = p2p_scan_ie_buf_len(drv->p2p);
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
-	if (ies == NULL) {
-		wpabuf_free(wps_ie);
-		return -1;
-	}
-	wpabuf_put_buf(ies, wps_ie);
-	wpabuf_free(wps_ie);
-
-	p2p_scan_ie(drv->p2p, ies, dev_id);
-
-	params.extra_ies = wpabuf_head(ies);
-	params.extra_ies_len = wpabuf_len(ies);
-
-	switch (type) {
-	case P2P_SCAN_SOCIAL:
-		params.freqs = social_channels;
-		break;
-	case P2P_SCAN_FULL:
-		break;
-	case P2P_SCAN_SOCIAL_PLUS_ONE:
-		social_channels[3] = freq;
-		params.freqs = social_channels;
-		break;
-	}
-
-	drv->pending_p2p_scan = 1;
-	ret = wpa_driver_test_scan(drv, &params);
-
-	wpabuf_free(ies);
-
-	return ret;
-}
-
-
-static int test_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)
-{
-	struct wpa_driver_test_data *drv = ctx;
-
-	wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR
-		   " bssid=" MACSTR " len=%d",
-		   __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
-		   (int) len);
-	if (freq <= 0) {
-		wpa_printf(MSG_WARNING, "P2P: No frequency specified for "
-			   "action frame TX");
-		return -1;
-	}
-
-	if (drv->pending_action_tx) {
-		wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
-			   "to " MACSTR, MAC2STR(drv->pending_action_dst));
-		wpabuf_free(drv->pending_action_tx);
-	}
-	drv->pending_action_tx = wpabuf_alloc(len);
-	if (drv->pending_action_tx == NULL)
-		return -1;
-	wpabuf_put_data(drv->pending_action_tx, buf, len);
-	os_memcpy(drv->pending_action_src, src, ETH_ALEN);
-	os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
-	os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
-	drv->pending_action_freq = freq;
-	drv->pending_action_no_cck = 1;
-
-	if (drv->off_channel_freq == freq) {
-		/* Already on requested channel; send immediately */
-		/* TODO: Would there ever be need to extend the current
-		 * duration on the channel? */
-		eloop_cancel_timeout(test_send_action_cb, drv, NULL);
-		eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL);
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
-		   "once the driver gets to the requested channel");
-	if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
-			   "to remain on channel (%u MHz) for Action "
-			   "Frame TX", freq);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void test_send_action_done(void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	/* TODO */
-}
-
-
-static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
-{
-	struct wpa_driver_test_data *drv = ctx;
-	union wpa_event_data event;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	os_memset(&event, 0, sizeof(event));
-	event.p2p_go_neg_completed.res = res;
-	wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event);
-}
-
-
-static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
-{
-	struct wpa_driver_test_data *drv = ctx;
-	union wpa_event_data event;
-	wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src));
-	os_memset(&event, 0, sizeof(event));
-	event.p2p_go_neg_req_rx.src = src;
-	event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id;
-	wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event);
-}
-
-
-static void test_dev_found(void *ctx, const u8 *addr,
-			   const struct p2p_peer_info *info, int new_device)
-{
-	struct wpa_driver_test_data *drv = ctx;
-	union wpa_event_data event;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-	wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR
-		   " pri_dev_type=%s name='%s' config_methods=0x%x "
-		   "dev_capab=0x%x group_capab=0x%x)",
-		   __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr),
-		   wps_dev_type_bin2str(info->pri_dev_type, devtype,
-					sizeof(devtype)),
-		   info->device_name, info->config_methods, info->dev_capab,
-		   info->group_capab);
-
-	os_memset(&event, 0, sizeof(event));
-	event.p2p_dev_found.addr = addr;
-	event.p2p_dev_found.dev_addr = info->p2p_device_addr;
-	event.p2p_dev_found.pri_dev_type = info->pri_dev_type;
-	event.p2p_dev_found.dev_name = info->device_name;
-	event.p2p_dev_found.config_methods = info->config_methods;
-	event.p2p_dev_found.dev_capab = info->dev_capab;
-	event.p2p_dev_found.group_capab = info->group_capab;
-	wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event);
-}
-
-
-static int test_start_listen(void *ctx, unsigned int freq,
-			     unsigned int duration,
-			     const struct wpabuf *probe_resp_ie)
-{
-	struct wpa_driver_test_data *drv = ctx;
-
-	wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)",
-		   __func__, freq, duration);
-
-	if (wpa_driver_test_probe_req_report(drv, 1) < 0)
-		return -1;
-
-	drv->pending_listen_freq = freq;
-	drv->pending_listen_duration = duration;
-
-	if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) {
-		drv->pending_listen_freq = 0;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void test_stop_listen(void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	/* TODO */
-}
-
-
-static int test_send_probe_resp(void *ctx, const struct wpabuf *buf)
-{
-	struct wpa_driver_test_data *drv = ctx;
-	char resp[512], *pos, *end;
-	int ret;
-	const struct ieee80211_mgmt *mgmt;
-	const u8 *ie, *ie_end;
-
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf);
-	if (wpabuf_len(buf) < 24)
-		return -1;
-	if (!drv->probe_from) {
-		wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__);
-		return -1;
-	}
-
-	pos = resp;
-	end = resp + sizeof(resp);
-
-	mgmt = wpabuf_head(buf);
-
-	/* reply: SCANRESP BSSID SSID IEs */
-	ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-			  MAC2STR(mgmt->bssid));
-	if (ret < 0 || ret >= end - pos)
-		return -1;
-	pos += ret;
-
-	ie = mgmt->u.probe_resp.variable;
-	ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf);
-	if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID ||
-	    ie + 2 + ie[1] > ie_end)
-		return -1;
-	pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]);
-
-	ret = os_snprintf(pos, end - pos, " ");
-	if (ret < 0 || ret >= end - pos)
-		return -1;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie);
-
-	sendto(drv->test_socket, resp, pos - resp, 0,
-	       drv->probe_from, drv->probe_from_len);
-
-	return 0;
-}
-
-
-static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
-			    u16 update_indic, const u8 *tlvs, size_t tlvs_len)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	/* TODO */
-}
-
-
-static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic,
-			     const u8 *tlvs, size_t tlvs_len)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	/* TODO */
-}
-
-
-static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
-			       const u8 *dev_addr, const u8 *pri_dev_type,
-			       const char *dev_name, u16 supp_config_methods,
-			       u8 dev_capab, u8 group_capab,
-			       const u8 *group_id, size_t group_id_len)
-{
-	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
-		   __func__, MAC2STR(peer), config_methods);
-	/* TODO */
-}
-
-
-static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
-{
-	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
-		   __func__, MAC2STR(peer), config_methods);
-	/* TODO */
-}
-
-
-static void test_p2p_debug_print(void *ctx, int level, const char *msg)
-{
-	wpa_printf(level, "P2P: %s", msg);
-}
-
-#endif /* CONFIG_P2P */
-
-
-static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv)
-{
-#ifdef CONFIG_P2P
-	struct p2p_config p2p;
-	unsigned int r;
-	int i;
-
-	os_memset(&p2p, 0, sizeof(p2p));
-	p2p.cb_ctx = drv;
-	p2p.debug_print = test_p2p_debug_print;
-	p2p.p2p_scan = test_p2p_scan;
-	p2p.send_action = test_send_action;
-	p2p.send_action_done = test_send_action_done;
-	p2p.go_neg_completed = test_go_neg_completed;
-	p2p.go_neg_req_rx = test_go_neg_req_rx;
-	p2p.dev_found = test_dev_found;
-	p2p.start_listen = test_start_listen;
-	p2p.stop_listen = test_stop_listen;
-	p2p.send_probe_resp = test_send_probe_resp;
-	p2p.sd_request = test_sd_request;
-	p2p.sd_response = test_sd_response;
-	p2p.prov_disc_req = test_prov_disc_req;
-	p2p.prov_disc_resp = test_prov_disc_resp;
-
-	os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN);
-
-	p2p.reg_class = 12; /* TODO: change depending on location */
-	/*
-	 * Pick one of the social channels randomly as the listen
-	 * channel.
-	 */
-	os_get_random((u8 *) &r, sizeof(r));
-	p2p.channel = 1 + (r % 3) * 5;
-
-	/* TODO: change depending on location */
-	p2p.op_reg_class = 12;
-	/*
-	 * For initial tests, pick the operation channel randomly.
-	 * TODO: Use scan results (etc.) to select the best channel.
-	 */
-	p2p.op_channel = 1 + r % 11;
-
-	os_memcpy(p2p.country, "US ", 3);
-
-	/* FIX: fetch available channels from the driver */
-	p2p.channels.reg_classes = 1;
-	p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */
-	p2p.channels.reg_class[0].channels = 11;
-	for (i = 0; i < 11; i++)
-		p2p.channels.reg_class[0].channel[i] = i + 1;
-
-	p2p.max_peers = 100;
-
-	drv->p2p = p2p_init(&p2p);
-	if (drv->p2p == NULL)
-		return -1;
-	return 0;
-#else /* CONFIG_P2P */
-	wpa_printf(MSG_INFO, "driver_test: P2P support not included");
-	return -1;
-#endif /* CONFIG_P2P */
-}
-
-
 const struct wpa_driver_ops wpa_driver_test_ops = {
 	"test",
 	"wpa_supplicant test driver",
@@ -3309,14 +2675,4 @@
 	.remain_on_channel = wpa_driver_test_remain_on_channel,
 	.cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
 	.probe_req_report = wpa_driver_test_probe_req_report,
-#ifdef CONFIG_P2P
-	.p2p_find = wpa_driver_test_p2p_find,
-	.p2p_stop_find = wpa_driver_test_p2p_stop_find,
-	.p2p_listen = wpa_driver_test_p2p_listen,
-	.p2p_connect = wpa_driver_test_p2p_connect,
-	.wps_success_cb = wpa_driver_test_wps_success_cb,
-	.p2p_group_formation_failed =
-	wpa_driver_test_p2p_group_formation_failed,
-	.p2p_set_params = wpa_driver_test_p2p_set_params,
-#endif /* CONFIG_P2P */
 };
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 1401050..e5734bd 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -31,10 +31,6 @@
 #include "driver.h"
 #include "driver_wext.h"
 
-#ifdef ANDROID
-#include "android_drv.h"
-#endif /* ANDROID */
-
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
@@ -299,14 +295,6 @@
 		}
 		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
 #endif /* CONFIG_PEERKEY */
-#ifdef ANDROID
-	} else if (os_strncmp(custom, "STOP", 4) == 0) {
-		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
-	} else if (os_strncmp(custom, "START", 5) == 0) {
-		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
-	} else if (os_strncmp(custom, "HANG", 4) == 0) {
-		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
-#endif /* ANDROID */
 	}
 }
 
@@ -858,12 +846,6 @@
 
 	drv->mlme_sock = -1;
 
-#ifdef ANDROID
-	drv->errors = 0;
-	drv->driver_is_started = TRUE;
-	drv->bgscan_enabled = 0;
-#endif /* ANDROID */
-
 	if (wpa_driver_wext_finish_drv_init(drv) < 0)
 		goto err3;
 
@@ -1869,10 +1851,8 @@
 {
 	struct iwreq iwr;
 	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-#ifndef ANDROID
 	u8 ssid[32];
 	int i;
-#endif /* ANDROID */
 
 	/*
 	 * Only force-disconnect when the card is in infrastructure mode,
@@ -1893,7 +1873,6 @@
 				   "selection on disconnect");
 		}
 
-#ifndef ANDROID
 		if (drv->cfg80211) {
 			/*
 			 * cfg80211 supports SIOCSIWMLME commands, so there is
@@ -1919,7 +1898,6 @@
 			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
 				   "SSID to disconnect");
 		}
-#endif /* ANDROID */
 	}
 }
 
@@ -1960,15 +1938,15 @@
 int wpa_driver_wext_cipher2wext(int cipher)
 {
 	switch (cipher) {
-	case CIPHER_NONE:
+	case WPA_CIPHER_NONE:
 		return IW_AUTH_CIPHER_NONE;
-	case CIPHER_WEP40:
+	case WPA_CIPHER_WEP40:
 		return IW_AUTH_CIPHER_WEP40;
-	case CIPHER_TKIP:
+	case WPA_CIPHER_TKIP:
 		return IW_AUTH_CIPHER_TKIP;
-	case CIPHER_CCMP:
+	case WPA_CIPHER_CCMP:
 		return IW_AUTH_CIPHER_CCMP;
-	case CIPHER_WEP104:
+	case WPA_CIPHER_WEP104:
 		return IW_AUTH_CIPHER_WEP104;
 	default:
 		return 0;
@@ -1979,10 +1957,10 @@
 int wpa_driver_wext_keymgmt2wext(int keymgmt)
 {
 	switch (keymgmt) {
-	case KEY_MGMT_802_1X:
-	case KEY_MGMT_802_1X_NO_WPA:
+	case WPA_KEY_MGMT_IEEE8021X:
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
 		return IW_AUTH_KEY_MGMT_802_1X;
-	case KEY_MGMT_PSK:
+	case WPA_KEY_MGMT_PSK:
 		return IW_AUTH_KEY_MGMT_PSK;
 	default:
 		return 0;
@@ -2099,9 +2077,9 @@
 	if (wpa_driver_wext_set_auth_param(drv,
 					   IW_AUTH_KEY_MGMT, value) < 0)
 		ret = -1;
-	value = params->key_mgmt_suite != KEY_MGMT_NONE ||
-		params->pairwise_suite != CIPHER_NONE ||
-		params->group_suite != CIPHER_NONE ||
+	value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
+		params->pairwise_suite != WPA_CIPHER_NONE ||
+		params->group_suite != WPA_CIPHER_NONE ||
 		params->wpa_ie_len;
 	if (wpa_driver_wext_set_auth_param(drv,
 					   IW_AUTH_PRIVACY_INVOKED, value) < 0)
@@ -2110,8 +2088,8 @@
 	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
 	 * not using WPA. IEEE 802.1X specifies that these frames are not
 	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
+	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
 		allow_unencrypted_eapol = 0;
 	else
 		allow_unencrypted_eapol = 1;
@@ -2338,129 +2316,6 @@
 }
 
 
-#ifdef ANDROID
-
-static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
-{
-	struct iwreq iwr;
-	char buf[MAX_DRV_CMD_SIZE];
-	int ret;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	os_memset(buf, 0, sizeof(buf));
-	os_strlcpy(buf, cmd, sizeof(buf));
-
-	iwr.u.data.pointer = buf;
-	iwr.u.data.length = sizeof(buf);
-
-	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
-
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
-			   cmd);
-		drv->errors++;
-		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
-			drv->errors = 0;
-			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
-				"HANGED");
-		}
-		return ret;
-	}
-
-	drv->errors = 0;
-	return 0;
-}
-
-
-static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
-			   u32 interval)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0, i = 0, bp;
-	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
-
-	bp = WEXT_PNOSETUP_HEADER_SIZE;
-	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
-	buf[bp++] = WEXT_PNO_TLV_PREFIX;
-	buf[bp++] = WEXT_PNO_TLV_VERSION;
-	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
-	buf[bp++] = WEXT_PNO_TLV_RESERVED;
-
-	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
-		/*
-		 * Check that there is enough space needed for 1 more SSID, the
-		 * other sections and null termination.
-		 */
-		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
-		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
-			break;
-
-		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
-				  params->ssids[i].ssid,
-				  params->ssids[i].ssid_len);
-		buf[bp++] = WEXT_PNO_SSID_SECTION;
-		buf[bp++] = params->ssids[i].ssid_len;
-		os_memcpy(&buf[bp], params->ssids[i].ssid,
-			  params->ssids[i].ssid_len);
-		bp += params->ssids[i].ssid_len;
-		i++;
-	}
-
-	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
-	/* TODO: consider using interval parameter (interval in msec) instead
-	 * of hardcoded value here */
-	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
-		    WEXT_PNO_SCAN_INTERVAL);
-	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
-
-	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
-	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
-		    WEXT_PNO_REPEAT);
-	bp += WEXT_PNO_REPEAT_LENGTH;
-
-	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
-	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
-		    WEXT_PNO_MAX_REPEAT);
-	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = buf;
-	iwr.u.data.length = bp;
-
-	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
-			   ret);
-		drv->errors++;
-		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
-			drv->errors = 0;
-			wpa_msg(drv->ctx, MSG_INFO,
-				WPA_EVENT_DRIVER_STATE "HANGED");
-		}
-		return ret;
-	}
-
-	drv->errors = 0;
-	drv->bgscan_enabled = 1;
-
-	return android_wext_cmd(drv, "PNOFORCE 1");
-}
-
-
-static int wext_stop_sched_scan(void *priv)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	drv->bgscan_enabled = 0;
-	return android_wext_cmd(drv, "PNOFORCE 0");
-}
-
-#endif /* ANDROID */
-
-
 const struct wpa_driver_ops wpa_driver_wext_ops = {
 	.name = "wext",
 	.desc = "Linux wireless extensions (generic)",
@@ -2480,8 +2335,4 @@
 	.get_capa = wpa_driver_wext_get_capa,
 	.set_operstate = wpa_driver_wext_set_operstate,
 	.get_radio_name = wext_get_radio_name,
-#ifdef ANDROID
-	.sched_scan = wext_sched_scan,
-	.stop_sched_scan = wext_stop_sched_scan,
-#endif /* ANDROID */
 };
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index c4a5bc9..b4b5960 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -44,12 +44,6 @@
 	int cfg80211; /* whether driver is using cfg80211 */
 
 	u8 max_level;
-
-#ifdef ANDROID
-	int errors;
-	int driver_is_started;
-	int bgscan_enabled;
-#endif /* ANDROID */
 };
 
 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index 04eb4fd..446ab63 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -6,8 +6,9 @@
  * See README for more details.
  */
 
-#include "includes.h"
-
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "driver.h"
 
 #ifdef CONFIG_DRIVER_WEXT
 extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 4380428..837971d 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -204,11 +204,14 @@
 int linux_br_get(char *brname, const char *ifname)
 {
 	char path[128], brlink[128], *pos;
+	ssize_t res;
+
 	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
 		    ifname);
-	os_memset(brlink, 0, sizeof(brlink));
-	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
+	res = readlink(path, brlink, sizeof(brlink));
+	if (res < 0 || (size_t) res >= sizeof(brlink))
 		return -1;
+	brlink[res] = '\0';
 	pos = os_strrchr(brlink, '/');
 	if (pos == NULL)
 		return -1;
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index 6c60550..2fa20b1 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -1,6 +1,6 @@
 /*
  * Netlink helper functions for driver wrappers
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -137,6 +137,35 @@
 	os_free(netlink);
 }
 
+
+static const char * linkmode_str(int mode)
+{
+	switch (mode) {
+	case -1:
+		return "no change";
+	case 0:
+		return "kernel-control";
+	case 1:
+		return "userspace-control";
+	}
+	return "?";
+}
+
+
+static const char * operstate_str(int state)
+{
+	switch (state) {
+	case -1:
+		return "no change";
+	case IF_OPER_DORMANT:
+		return "IF_OPER_DORMANT";
+	case IF_OPER_UP:
+		return "IF_OPER_UP";
+	}
+	return "?";
+}
+
+
 int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
 			   int linkmode, int operstate)
 {
@@ -184,8 +213,9 @@
 			RTA_LENGTH(sizeof(char));
 	}
 
-	wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
-		   linkmode, operstate);
+	wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
+		   ifindex, linkmode, linkmode_str(linkmode),
+		   operstate, operstate_str(operstate));
 
 	ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
 	if (ret < 0) {
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 32b060e..a12e6ca 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -126,6 +126,31 @@
  */
 
 /**
+ * DOC: packet coalesce support
+ *
+ * In most cases, host that receives IPv4 and IPv6 multicast/broadcast
+ * packets does not do anything with these packets. Therefore the
+ * reception of these unwanted packets causes unnecessary processing
+ * and power consumption.
+ *
+ * Packet coalesce feature helps to reduce number of received interrupts
+ * to host by buffering these packets in firmware/hardware for some
+ * predefined time. Received interrupt will be generated when one of the
+ * following events occur.
+ * a) Expiration of hardware timer whose expiration time is set to maximum
+ * coalescing delay of matching coalesce rule.
+ * b) Coalescing buffer in hardware reaches it's limit.
+ * c) Packet doesn't match any of the configured coalesce rules.
+ *
+ * User needs to configure following parameters for creating a coalesce
+ * rule.
+ * a) Maximum coalescing delay
+ * b) List of packet patterns which needs to be matched
+ * c) Condition for coalescence. pattern 'match' or 'no match'
+ * Multiple such rules can be created.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -393,8 +418,18 @@
  *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
  *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
  *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
- *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
- *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ *	%NL80211_ATTR_WIPHY_FREQ_HINT.
+ *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
+ *	restrictions on BSS selection, i.e., they effectively prevent roaming
+ *	within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT
+ *	can be included to provide a recommendation of the initial BSS while
+ *	allowing the driver to roam to other BSSes within the ESS and also to
+ *	ignore this recommendation if the indicated BSS is not ideal. Only one
+ *	set of BSSID,frequency parameters is used (i.e., either the enforcing
+ *	%NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ *	%NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
  *	Background scan period can optionally be
  *	specified in %NL80211_ATTR_BG_SCAN_PERIOD,
  *	if not specified default background scan configuration
@@ -556,7 +591,14 @@
  *	operation, %NL80211_ATTR_MAC contains the peer MAC address, and
  *	%NL80211_ATTR_REASON_CODE the reason code to be used (only with
  *	%NL80211_TDLS_TEARDOWN).
- * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The
+ *	%NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be
+ *	sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as
+ *	802.11 management frames, while TDLS action codes (802.11-2012
+ *	8.5.13.1) will be encapsulated and sent as data frames. The currently
+ *	supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES
+ *	and the currently supported TDLS actions codes are given in
+ *	&enum ieee80211_tdls_actioncode.
  *
  * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
  *	(or GO) interface (i.e. hostapd) to ask for unexpected frames to
@@ -648,6 +690,34 @@
  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
  *	return back to normal.
  *
+ * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
+ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
+ *
+ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
+ *	the new channel information (Channel Switch Announcement - CSA)
+ *	in the beacon for some time (as defined in the
+ *	%NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
+ *	new channel. Userspace provides the new channel information (using
+ *	%NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
+ *	width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
+ *	other station that transmission must be blocked until the channel
+ *	switch is complete.
+ *
+ * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified
+ *	by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in
+ *	%NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in
+ *	%NL80211_ATTR_VENDOR_DATA.
+ *	For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is
+ *	used in the wiphy data as a nested attribute containing descriptions
+ *	(&struct nl80211_vendor_cmd_info) of the supported vendor commands.
+ *	This may also be sent as an event with the same attributes.
+ *
+ * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
+ *	The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
+ *	that attribute is not included, QoS mapping is disabled. Since this
+ *	QoS mapping is relevant for IP packets, it is only valid during an
+ *	association. This is cleared on disassociation and AP restart.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -810,6 +880,15 @@
 	NL80211_CMD_CRIT_PROTOCOL_START,
 	NL80211_CMD_CRIT_PROTOCOL_STOP,
 
+	NL80211_CMD_GET_COALESCE,
+	NL80211_CMD_SET_COALESCE,
+
+	NL80211_CMD_CHANNEL_SWITCH,
+
+	NL80211_CMD_VENDOR,
+
+	NL80211_CMD_SET_QOS_MAP,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -945,7 +1024,7 @@
  * 	to query the CRDA to retrieve one regulatory domain. This attribute can
  * 	also be used by userspace to query the kernel for the currently set
  * 	regulatory domain. We chose an alpha2 as that is also used by the
- * 	IEEE-802.11d country information element to identify a country.
+ * 	IEEE-802.11 country information element to identify a country.
  * 	Users can also simply ask the wireless core to set regulatory domain
  * 	to a specific alpha2.
  * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
@@ -1436,6 +1515,66 @@
  *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
  *	update a TDLS peer STA entry.
  *
+ * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
+ *
+ * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
+ *	until the channel switch event.
+ * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
+ *	must be blocked on the current channel (before the channel switch
+ *	operation).
+ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
+ *	for the time while performing a channel switch.
+ * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
+ *	field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
+ *	field in the probe response (%NL80211_ATTR_PROBE_RESP).
+ *
+ * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
+ *	As specified in the &enum nl80211_rxmgmt_flags.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
+ *      supported operating classes.
+ *
+ * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
+ *	controls DFS operation in IBSS mode. If the flag is included in
+ *	%NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
+ *	channels and reports radar events to userspace. Userspace is required
+ *	to react to radar events, e.g. initiate a channel switch or leave the
+ *	IBSS network.
+ *
+ * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports
+ *	5 MHz channel bandwidth.
+ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
+ *	10 MHz channel bandwidth.
+ *
+ * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
+ *	Notification Element based on association request when used with
+ *	%NL80211_CMD_NEW_STATION; u8 attribute.
+ *
+ * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
+ *	%NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
+ * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
+ * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
+ *	attribute is also used for vendor command feature advertisement
+ * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
+ *	info, containing a nested array of possible events
+ *
+ * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
+ *	data is in the format defined for the payload of the QoS Map Set element
+ *	in IEEE Std 802.11-2012, 8.4.2.97.
+ *
+ * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS
+ * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS
+ *
+ * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many
+ *	associated stations are supported in AP mode (including P2P GO); u32.
+ *	Since drivers may not have a fixed limit on the maximum number (e.g.,
+ *	other concurrent operations may affect this), drivers are allowed to
+ *	advertise values that cannot always be met. In such cases, an attempt
+ *	to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1736,6 +1875,39 @@
 
 	NL80211_ATTR_PEER_AID,
 
+	NL80211_ATTR_COALESCE_RULE,
+
+	NL80211_ATTR_CH_SWITCH_COUNT,
+	NL80211_ATTR_CH_SWITCH_BLOCK_TX,
+	NL80211_ATTR_CSA_IES,
+	NL80211_ATTR_CSA_C_OFF_BEACON,
+	NL80211_ATTR_CSA_C_OFF_PRESP,
+
+	NL80211_ATTR_RXMGMT_FLAGS,
+
+	NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+
+	NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+
+	NL80211_ATTR_HANDLE_DFS,
+
+	NL80211_ATTR_SUPPORT_5_MHZ,
+	NL80211_ATTR_SUPPORT_10_MHZ,
+
+	NL80211_ATTR_OPMODE_NOTIF,
+
+	NL80211_ATTR_VENDOR_ID,
+	NL80211_ATTR_VENDOR_SUBCMD,
+	NL80211_ATTR_VENDOR_DATA,
+	NL80211_ATTR_VENDOR_EVENTS,
+
+	NL80211_ATTR_QOS_MAP,
+
+	NL80211_ATTR_MAC_HINT,
+	NL80211_ATTR_WIPHY_FREQ_HINT,
+
+	NL80211_ATTR_MAX_AP_ASSOC_STA,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2136,10 +2308,9 @@
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
  * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
  *	regulatory domain.
- * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
- *	permitted on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
- *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation
+ * 	are permitted on this channel, this includes sending probe
+ * 	requests, or modes of operation that require beaconing.
  * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
  *	on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
@@ -2166,8 +2337,8 @@
 	__NL80211_FREQUENCY_ATTR_INVALID,
 	NL80211_FREQUENCY_ATTR_FREQ,
 	NL80211_FREQUENCY_ATTR_DISABLED,
-	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
-	NL80211_FREQUENCY_ATTR_NO_IBSS,
+	NL80211_FREQUENCY_ATTR_NO_IR,
+	__NL80211_FREQUENCY_ATTR_NO_IBSS,
 	NL80211_FREQUENCY_ATTR_RADAR,
 	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
 	NL80211_FREQUENCY_ATTR_DFS_STATE,
@@ -2183,6 +2354,9 @@
 };
 
 #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN	NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IBSS		NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IR		NL80211_FREQUENCY_ATTR_NO_IR
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
@@ -2263,7 +2437,10 @@
  * 	in KHz. This is not a center a frequency but an actual regulatory
  * 	band edge.
  * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
- * 	frequency range, in KHz.
+ *	frequency range, in KHz. If not present or 0, maximum available
+ *	bandwidth should be calculated base on contiguous rules and wider
+ *	channels will be allowed to cross multiple contiguous/overlapping
+ *	frequency ranges.
  * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
  * 	for a given frequency range. The value is in mBi (100 * dBi).
  * 	If you don't have one then don't send this.
@@ -2293,9 +2470,15 @@
  * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
- * only report BSS with matching SSID.
+ *	only report BSS with matching SSID.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
- *	BSS in scan results. Filtering is turned off if not specified.
+ *	BSS in scan results. Filtering is turned off if not specified. Note that
+ *	if this attribute is in a match set of its own, then it is treated as
+ *	the default value for all matchsets with an SSID, rather than being a
+ *	matchset of its own without an RSSI filter. This is due to problems with
+ *	how this API was implemented in the past. Also, due to the same problem,
+ *	the only way to create a matchset with only an RSSI filter (with this
+ *	attribute) is if there's only a single matchset with the RSSI attribute.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *	attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -2325,8 +2508,9 @@
  * @NL80211_RRF_DFS: DFS support is required to be used
  * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
  * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
- * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
- * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
+ * 	this includes probe requests or modes of operation that require
+ * 	beaconing.
  */
 enum nl80211_reg_rule_flags {
 	NL80211_RRF_NO_OFDM		= 1<<0,
@@ -2336,10 +2520,17 @@
 	NL80211_RRF_DFS			= 1<<4,
 	NL80211_RRF_PTP_ONLY		= 1<<5,
 	NL80211_RRF_PTMP_ONLY		= 1<<6,
-	NL80211_RRF_PASSIVE_SCAN	= 1<<7,
-	NL80211_RRF_NO_IBSS		= 1<<8,
+	NL80211_RRF_NO_IR		= 1<<7,
+	__NL80211_RRF_NO_IBSS		= 1<<8,
 };
 
+#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
+
+/* For backport compatibility with older userspace */
+#define NL80211_RRF_NO_IR_ALL		(NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
+
 /**
  * enum nl80211_dfs_regions - regulatory DFS regions
  *
@@ -2428,6 +2619,8 @@
  * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
  * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
  *	overrides all other flags.
+ * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
+ *	and ACK incoming unicast packets.
  *
  * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
  * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -2439,6 +2632,7 @@
 	NL80211_MNTR_FLAG_CONTROL,
 	NL80211_MNTR_FLAG_OTHER_BSS,
 	NL80211_MNTR_FLAG_COOK_FRAMES,
+	NL80211_MNTR_FLAG_ACTIVE,
 
 	/* keep last */
 	__NL80211_MNTR_FLAG_AFTER_LAST,
@@ -2574,6 +2768,10 @@
  *
  * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
  *
+ * @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.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2605,6 +2803,7 @@
 	NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
 	NL80211_MESHCONF_POWER_MODE,
 	NL80211_MESHCONF_AWAKE_WINDOW,
+	NL80211_MESHCONF_PLINK_TIMEOUT,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2750,6 +2949,8 @@
  *	and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
  * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
  *	attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
  */
 enum nl80211_chan_width {
 	NL80211_CHAN_WIDTH_20_NOHT,
@@ -2758,6 +2959,23 @@
 	NL80211_CHAN_WIDTH_80,
 	NL80211_CHAN_WIDTH_80P80,
 	NL80211_CHAN_WIDTH_160,
+	NL80211_CHAN_WIDTH_5,
+	NL80211_CHAN_WIDTH_10,
+};
+
+/**
+ * enum nl80211_bss_scan_width - control channel width for a BSS
+ *
+ * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute.
+ *
+ * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible
+ * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide
+ */
+enum nl80211_bss_scan_width {
+	NL80211_BSS_CHAN_WIDTH_20,
+	NL80211_BSS_CHAN_WIDTH_10,
+	NL80211_BSS_CHAN_WIDTH_5,
 };
 
 /**
@@ -2784,6 +3002,8 @@
  * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
  *	elements from a Beacon frame (bin); not present if no Beacon frame has
  *	yet been received
+ * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
+ *	(u32, enum nl80211_bss_scan_width)
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -2800,6 +3020,7 @@
 	NL80211_BSS_STATUS,
 	NL80211_BSS_SEEN_MS_AGO,
 	NL80211_BSS_BEACON_IES,
+	NL80211_BSS_CHAN_WIDTH,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -2940,21 +3161,43 @@
  *	in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
  *	1 = 500 kbps) but without the IE length restriction (at most
  *	%NL80211_MAX_SUPP_RATES in a single array).
- * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection
  *	in an array of MCS numbers.
+ * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
+ *	see &struct nl80211_txrate_vht
+ * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi
  * @__NL80211_TXRATE_AFTER_LAST: internal
  * @NL80211_TXRATE_MAX: highest TX rate attribute
  */
 enum nl80211_tx_rate_attributes {
 	__NL80211_TXRATE_INVALID,
 	NL80211_TXRATE_LEGACY,
-	NL80211_TXRATE_MCS,
+	NL80211_TXRATE_HT,
+	NL80211_TXRATE_VHT,
+	NL80211_TXRATE_GI,
 
 	/* keep last */
 	__NL80211_TXRATE_AFTER_LAST,
 	NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
 };
 
+#define NL80211_TXRATE_MCS NL80211_TXRATE_HT
+#define NL80211_VHT_NSS_MAX		8
+
+/**
+ * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap
+ * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
+ */
+struct nl80211_txrate_vht {
+	__u16 mcs[NL80211_VHT_NSS_MAX];
+};
+
+enum nl80211_txrate_gi {
+	NL80211_TXRATE_DEFAULT_GI,
+	NL80211_TXRATE_FORCE_SGI,
+	NL80211_TXRATE_FORCE_LGI,
+};
+
 /**
  * enum nl80211_band - Frequency band
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
@@ -3048,11 +3291,11 @@
 };
 
 /**
- * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
- * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
- * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ * enum nl80211_packet_pattern_attr - packet pattern attribute
+ * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
  *	a zero bit are ignored
- * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have
  *	a bit for each byte in the pattern. The lowest-order bit corresponds
  *	to the first byte of the pattern, but the bytes of the pattern are
  *	in a little-endian-like format, i.e. the 9th byte of the pattern
@@ -3063,39 +3306,50 @@
  *	Note that the pattern matching is done as though frames were not
  *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
  *	first (including SNAP header unpacking) and then matched.
- * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after
  *	these fixed number of bytes of received packet
- * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
- * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ * @NUM_NL80211_PKTPAT: number of attributes
+ * @MAX_NL80211_PKTPAT: max attribute number
  */
-enum nl80211_wowlan_packet_pattern_attr {
-	__NL80211_WOWLAN_PKTPAT_INVALID,
-	NL80211_WOWLAN_PKTPAT_MASK,
-	NL80211_WOWLAN_PKTPAT_PATTERN,
-	NL80211_WOWLAN_PKTPAT_OFFSET,
+enum nl80211_packet_pattern_attr {
+	__NL80211_PKTPAT_INVALID,
+	NL80211_PKTPAT_MASK,
+	NL80211_PKTPAT_PATTERN,
+	NL80211_PKTPAT_OFFSET,
 
-	NUM_NL80211_WOWLAN_PKTPAT,
-	MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+	NUM_NL80211_PKTPAT,
+	MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1,
 };
 
 /**
- * struct nl80211_wowlan_pattern_support - pattern support information
+ * struct nl80211_pattern_support - packet pattern support information
  * @max_patterns: maximum number of patterns supported
  * @min_pattern_len: minimum length of each pattern
  * @max_pattern_len: maximum length of each pattern
  * @max_pkt_offset: maximum Rx packet offset
  *
  * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
- * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
- * capability information given by the kernel to userspace.
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in
+ * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of
+ * %NL80211_ATTR_COALESCE_RULE in the capability information given
+ * by the kernel to userspace.
  */
-struct nl80211_wowlan_pattern_support {
+struct nl80211_pattern_support {
 	__u32 max_patterns;
 	__u32 min_pattern_len;
 	__u32 max_pattern_len;
 	__u32 max_pkt_offset;
 } __attribute__((packed));
 
+/* only for backward compatibility */
+#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID
+#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK
+#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN
+#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET
+#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT
+#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT
+#define nl80211_wowlan_pattern_support nl80211_pattern_support
+
 /**
  * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
  * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
@@ -3115,7 +3369,7 @@
  *	pattern matching is done after the packet is converted to the MSDU.
  *
  *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
- *	carrying a &struct nl80211_wowlan_pattern_support.
+ *	carrying a &struct nl80211_pattern_support.
  *
  *	When reporting wakeup. it is a u32 attribute containing the 0-based
  *	index of the pattern that caused the wakeup, in the patterns passed
@@ -3272,7 +3526,7 @@
  * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
  *	u32 attribute holding the maximum length
  * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
- *	feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ *	feature advertising. The mask works like @NL80211_PKTPAT_MASK
  *	but on the TCP payload only.
  * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
  * @MAX_NL80211_WOWLAN_TCP: highest attribute number
@@ -3297,6 +3551,55 @@
 };
 
 /**
+ * struct nl80211_coalesce_rule_support - coalesce rule support information
+ * @max_rules: maximum number of rules supported
+ * @pat: packet pattern support information
+ * @max_delay: maximum supported coalescing delay in msecs
+ *
+ * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_coalesce_rule_support {
+	__u32 max_rules;
+	struct nl80211_pattern_support pat;
+	__u32 max_delay;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_attr_coalesce_rule - coalesce rule attribute
+ * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute
+ * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing
+ * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence,
+ *	see &enum nl80211_coalesce_condition.
+ * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched
+ *	after these fixed number of bytes of received packet
+ * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes
+ * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number
+ */
+enum nl80211_attr_coalesce_rule {
+	__NL80211_COALESCE_RULE_INVALID,
+	NL80211_ATTR_COALESCE_RULE_DELAY,
+	NL80211_ATTR_COALESCE_RULE_CONDITION,
+	NL80211_ATTR_COALESCE_RULE_PKT_PATTERN,
+
+	/* keep last */
+	NUM_NL80211_ATTR_COALESCE_RULE,
+	NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1
+};
+
+/**
+ * enum nl80211_coalesce_condition - coalesce rule conditions
+ * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns
+ *	in a rule are matched.
+ * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns
+ *	in a rule are not matched.
+ */
+enum nl80211_coalesce_condition {
+	NL80211_COALESCE_CONDITION_MATCH,
+	NL80211_COALESCE_CONDITION_NO_MATCH
+};
+
+/**
  * enum nl80211_iface_limit_attrs - limit attributes
  * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
  * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
@@ -3576,6 +3879,10 @@
  *	Peering Management entity which may be implemented by registering for
  *	beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
  *	still generated by the driver.
+ * @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor
+ *	interface. An active monitor interface behaves like a normal monitor
+ *	interface, but gets added to the driver. It ensures that incoming
+ *	unicast packets directed at the configured interface address get ACKed.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -3595,6 +3902,7 @@
 	NL80211_FEATURE_ADVERTISE_CHAN_LIMITS		= 1 << 14,
 	NL80211_FEATURE_FULL_AP_CLIENT_STATE		= 1 << 15,
 	NL80211_FEATURE_USERSPACE_MPM			= 1 << 16,
+	NL80211_FEATURE_ACTIVE_MONITOR			= 1 << 17,
 };
 
 /**
@@ -3695,13 +4003,12 @@
  *
  * Channel states used by the DFS code.
  *
- * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
+ * @NL80211_DFS_USABLE: The channel can be used, but channel availability
  *	check (CAC) must be performed before using it for AP or IBSS.
- * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
+ * @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
  *	is therefore marked as not available.
- * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
+ * @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
  */
-
 enum nl80211_dfs_state {
 	NL80211_DFS_USABLE,
 	NL80211_DFS_UNAVAILABLE,
@@ -3741,4 +4048,35 @@
 /* maximum duration for critical protocol measures */
 #define NL80211_CRIT_PROTO_MAX_DURATION		5000 /* msec */
 
+/**
+ * enum nl80211_rxmgmt_flags - flags for received management frame.
+ *
+ * Used by cfg80211_rx_mgmt()
+ *
+ * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver.
+ */
+enum nl80211_rxmgmt_flags {
+	NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0,
+};
+
+/*
+ * If this flag is unset, the lower 24 bits are an OUI, if set
+ * a Linux nl80211 vendor ID is used (no such IDs are allocated
+ * yet, so that's not valid so far)
+ */
+#define NL80211_VENDOR_ID_IS_LINUX	0x80000000
+
+/**
+ * struct nl80211_vendor_cmd_info - vendor command data
+ * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the
+ *	value is a 24-bit OUI; if it is set then a separately allocated ID
+ *	may be used, but no such IDs are allocated yet. New IDs should be
+ *	added to this file when needed.
+ * @subcmd: sub-command ID for the command
+ */
+struct nl80211_vendor_cmd_info {
+	__u32 vendor_id;
+	__u32 subcmd;
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
index 74d6ce5..6232088 100644
--- a/src/drivers/priv_netlink.h
+++ b/src/drivers/priv_netlink.h
@@ -69,6 +69,7 @@
 (struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
 #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
 #define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0))
 
 
 struct sockaddr_nl
diff --git a/src/eap_common/Makefile b/src/eap_common/Makefile
index 9c41962..adfd3df 100644
--- a/src/eap_common/Makefile
+++ b/src/eap_common/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index 376fcad..f061866 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -21,7 +21,7 @@
 	{ AUTH_HMAC_MD5_96, 16, 12 }
 };
 
-#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
+#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs)
 
 
 static struct ikev2_prf_alg ikev2_prf_algs[] = {
@@ -29,7 +29,7 @@
 	{ PRF_HMAC_MD5, 16, 16 }
 };
 
-#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
+#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs)
 
 
 static struct ikev2_encr_alg ikev2_encr_algs[] = {
@@ -37,7 +37,7 @@
 	{ ENCR_3DES, 24, 8 }
 };
 
-#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
+#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs)
 
 
 const struct ikev2_integ_alg * ikev2_get_integ(int id)
diff --git a/src/eap_peer/Makefile b/src/eap_peer/Makefile
index 3651056..f79519b 100644
--- a/src/eap_peer/Makefile
+++ b/src/eap_peer/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.so *.d
+	rm -f *~ *.o *.so *.d *.gcno *.gcda *.gcov
 
 install:
 	if ls *.so >/dev/null 2>&1; then \
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 554e7e9..47cbbee 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -179,6 +179,7 @@
 	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
 	sm->num_rounds = 0;
 	sm->prev_failure = 0;
+	sm->expected_failure = 0;
 }
 
 
@@ -388,10 +389,11 @@
 	sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
 					 eapReqData);
 	wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
-		   "methodState=%s decision=%s",
+		   "methodState=%s decision=%s eapRespData=%p",
 		   ret.ignore ? "TRUE" : "FALSE",
 		   eap_sm_method_state_txt(ret.methodState),
-		   eap_sm_decision_txt(ret.decision));
+		   eap_sm_decision_txt(ret.decision),
+		   sm->eapRespData);
 
 	sm->ignore = ret.ignore;
 	if (sm->ignore)
@@ -432,8 +434,10 @@
 		sm->lastId = sm->reqId;
 		sm->lastRespData = wpabuf_dup(sm->eapRespData);
 		eapol_set_bool(sm, EAPOL_eapResp, TRUE);
-	} else
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
 		sm->lastRespData = NULL;
+	}
 	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
 }
@@ -724,8 +728,19 @@
 			SM_ENTER(EAP, SEND_RESPONSE);
 		break;
 	case EAP_METHOD:
+		/*
+		 * Note: RFC 4137 uses methodState == DONE && decision == FAIL
+		 * as the condition. eapRespData == NULL here is used to allow
+		 * final EAP method response to be sent without having to change
+		 * all methods to either use methodState MAY_CONT or leaving
+		 * decision to something else than FAIL in cases where the only
+		 * expected response is EAP-Failure.
+		 */
 		if (sm->ignore)
 			SM_ENTER(EAP, DISCARD);
+		else if (sm->methodState == METHOD_DONE &&
+			 sm->decision == DECISION_FAIL && !sm->eapRespData)
+			SM_ENTER(EAP, FAILURE);
 		else
 			SM_ENTER(EAP, SEND_RESPONSE);
 		break;
@@ -1638,7 +1653,8 @@
 			   const char *msg, size_t msglen)
 {
 	struct eap_peer_config *config;
-	char *txt = NULL, *tmp;
+	const char *txt = NULL;
+	char *tmp;
 
 	if (sm == NULL)
 		return;
@@ -1681,6 +1697,9 @@
 	case WPA_CTRL_REQ_EAP_PASSPHRASE:
 		config->pending_req_passphrase++;
 		break;
+	case WPA_CTRL_REQ_SIM:
+		txt = msg;
+		break;
 	default:
 		return;
 	}
@@ -1792,6 +1811,17 @@
 
 
 /**
+ * eap_sm_request_sim - Request external SIM processing
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @req: EAP method specific request
+ */
+void eap_sm_request_sim(struct eap_sm *sm, const char *req)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req));
+}
+
+
+/**
  * eap_sm_notify_ctrl_attached - Notification of attached monitor
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  *
@@ -2017,6 +2047,8 @@
 	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
 		if (eap_get_ext_password(sm, config) < 0)
 			return NULL;
+		if (hash)
+			*hash = 0;
 		*len = wpabuf_len(sm->ext_pw_buf);
 		return wpabuf_head(sm->ext_pw_buf);
 	}
@@ -2304,6 +2336,17 @@
 }
 
 
+/**
+ * eap_set_external_sim - Set external_sim flag
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @external_sim: Whether external SIM/USIM processing is used
+ */
+void eap_set_external_sim(struct eap_sm *sm, int external_sim)
+{
+	sm->external_sim = external_sim;
+}
+
+
  /**
  * eap_notify_pending - Notify that EAP method is ready to re-process a request
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -2375,3 +2418,9 @@
 	if (sm->eapol_cb->set_anon_id)
 		sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
 }
+
+
+int eap_peer_was_failure_expected(struct eap_sm *sm)
+{
+	return sm->expected_failure;
+}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index f87f9b3..712e929 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -296,6 +296,7 @@
 void eap_sm_request_pin(struct eap_sm *sm);
 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
 void eap_sm_request_passphrase(struct eap_sm *sm);
+void eap_sm_request_sim(struct eap_sm *sm, const char *req);
 void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
 u32 eap_get_phase2_type(const char *name, int *vendor);
 struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
@@ -303,6 +304,7 @@
 void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
 void eap_set_force_disabled(struct eap_sm *sm, int disabled);
+void eap_set_external_sim(struct eap_sm *sm, int external_sim);
 int eap_key_available(struct eap_sm *sm);
 void eap_notify_success(struct eap_sm *sm);
 void eap_notify_lower_layer_success(struct eap_sm *sm);
@@ -318,6 +320,7 @@
 struct ext_password_data;
 void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
 void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+int eap_peer_was_failure_expected(struct eap_sm *sm);
 
 #endif /* IEEE8021X_EAPOL */
 
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index dc424d7..d3cbaca 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -142,6 +142,89 @@
 }
 
 
+static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
+{
+	char req[200], *pos, *end;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing");
+	pos = req;
+	end = pos + sizeof(req);
+	pos += os_snprintf(pos, end - pos, "UMTS-AUTH");
+	pos += os_snprintf(pos, end - pos, ":");
+	pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
+	pos += os_snprintf(pos, end - pos, ":");
+	pos += wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
+
+	eap_sm_request_sim(sm, req);
+	return 1;
+}
+
+
+static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data,
+				  struct eap_peer_config *conf)
+{
+	char *resp, *pos;
+
+	wpa_printf(MSG_DEBUG,
+		   "EAP-AKA: Use result from external USIM processing");
+
+	resp = conf->external_sim_resp;
+	conf->external_sim_resp = NULL;
+
+	if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) {
+		pos = resp + 10;
+		if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts,
+				EAP_AKA_AUTS_LEN);
+		os_free(resp);
+		return -2;
+	}
+
+	if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response");
+		os_free(resp);
+		return -1;
+	}
+
+	pos = resp + 10;
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN);
+
+	if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN);
+	pos += EAP_AKA_IK_LEN * 2;
+	if (*pos != ':')
+		goto invalid;
+	pos++;
+
+	if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN);
+	pos += EAP_AKA_CK_LEN * 2;
+	if (*pos != ':')
+		goto invalid;
+	pos++;
+
+	data->res_len = os_strlen(pos) / 2;
+	if (data->res_len > EAP_AKA_RES_MAX_LEN) {
+		data->res_len = 0;
+		goto invalid;
+	}
+	if (hexstr2bin(pos, data->res, data->res_len) < 0)
+		goto invalid;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len);
+
+	os_free(resp);
+	return 0;
+
+invalid:
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response");
+	os_free(resp);
+	return -1;
+}
+
+
 static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 {
 	struct eap_peer_config *conf;
@@ -151,6 +234,14 @@
 	conf = eap_get_config(sm);
 	if (conf == NULL)
 		return -1;
+
+	if (sm->external_sim) {
+		if (conf->external_sim_resp)
+			return eap_aka_ext_sim_result(sm, data, conf);
+		else
+			return eap_aka_ext_sim_req(sm, data);
+	}
+
 	if (conf->pcsc) {
 		return scard_umts_auth(sm->scard_ctx, data->rand,
 				       data->autn, data->res, &data->res_len,
@@ -861,6 +952,9 @@
 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
 			   "failed (AUTN seq# -> AUTS)");
 		return eap_aka_synchronization_failure(data, id);
+	} else if (res > 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
+		return NULL;
 	} else if (res) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
 		return eap_aka_client_error(data, id,
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 42f525b..98ec1f7 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -208,6 +208,24 @@
 	u8 *altsubject_match;
 
 	/**
+	 * domain_suffix_match - Constraint for server domain name
+	 *
+	 * 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
+	 * using same suffix match comparison. Suffix match here means that the
+	 * host/domain name is compared one label at a time starting from the
+	 * top-level domain and all the labels in domain_suffix_match shall be
+	 * included in the certificate. The certificate may include additional
+	 * sub-level labels in addition to the required labels.
+	 *
+	 * For example, domain_suffix_match=example.com would match
+	 * test.example.com but would not match test-example.com.
+	 */
+	char *domain_suffix_match;
+
+	/**
 	 * 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
@@ -303,6 +321,14 @@
 	u8 *altsubject_match2;
 
 	/**
+	 * domain_suffix_match2 - Constraint for server domain name
+	 *
+	 * This field is like domain_suffix_match, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	char *domain_suffix_match2;
+
+	/**
 	 * eap_methods - Allowed EAP methods
 	 *
 	 * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
@@ -643,6 +669,15 @@
 	 * 2 = require valid OCSP stapling response
 	 */
 	int ocsp;
+
+	/**
+	 * external_sim_resp - Response from external SIM processing
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request external
+	 * SIM/USIM processing.
+	 */
+	char *external_sim_resp;
 };
 
 
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
index c71db5f..864ea1d 100644
--- a/src/eap_peer/eap_eke.c
+++ b/src/eap_peer/eap_eke.c
@@ -28,6 +28,10 @@
 	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
 	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
 	struct wpabuf *msgs;
+	u8 dhgroup; /* forced DH group or 0 to allow all supported */
+	u8 encr; /* forced encryption algorithm or 0 to allow all supported */
+	u8 prf; /* forced PRF or 0 to allow all supported */
+	u8 mac; /* forced MAC or 0 to allow all supported */
 };
 
 
@@ -66,6 +70,7 @@
 	struct eap_eke_data *data;
 	const u8 *identity, *password;
 	size_t identity_len, password_len;
+	const char *phase1;
 
 	password = eap_get_config_password(sm, &password_len);
 	if (!password) {
@@ -89,6 +94,39 @@
 		data->peerid_len = identity_len;
 	}
 
+	phase1 = eap_get_config_phase1(sm);
+	if (phase1) {
+		const char *pos;
+
+		pos = os_strstr(phase1, "dhgroup=");
+		if (pos) {
+			data->dhgroup = atoi(pos + 8);
+			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
+				   data->dhgroup);
+		}
+
+		pos = os_strstr(phase1, "encr=");
+		if (pos) {
+			data->encr = atoi(pos + 5);
+			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
+				   data->encr);
+		}
+
+		pos = os_strstr(phase1, "prf=");
+		if (pos) {
+			data->prf = atoi(pos + 4);
+			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
+				   data->prf);
+		}
+
+		pos = os_strstr(phase1, "mac=");
+		if (pos) {
+			data->mac = atoi(pos + 4);
+			wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
+				   data->mac);
+		}
+	}
+
 	return data;
 }
 
@@ -226,16 +264,20 @@
 			   i, pos[0], pos[1], pos[2], pos[3]);
 		pos += 4;
 
-		if (!eap_eke_supp_dhgroup(*tmp))
+		if ((data->dhgroup && data->dhgroup != *tmp) ||
+		    !eap_eke_supp_dhgroup(*tmp))
 			continue;
 		tmp++;
-		if (!eap_eke_supp_encr(*tmp))
+		if ((data->encr && data->encr != *tmp) ||
+		    !eap_eke_supp_encr(*tmp))
 			continue;
 		tmp++;
-		if (!eap_eke_supp_prf(*tmp))
+		if ((data->prf && data->prf != *tmp) ||
+		    !eap_eke_supp_prf(*tmp))
 			continue;
 		tmp++;
-		if (!eap_eke_supp_mac(*tmp))
+		if ((data->mac && data->mac != *tmp) ||
+		    !eap_eke_supp_mac(*tmp))
 			continue;
 
 		prop = tmp - 3;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 3b8d803..1b0c562 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -196,14 +196,22 @@
 			   "workarounds");
 	}
 
+	if (!config->pac_file) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No PAC file configured");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
 	if (data->use_pac_binary_format &&
 	    eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
 		eap_fast_deinit(sm, data);
 		return NULL;
 	}
 
 	if (!data->use_pac_binary_format &&
 	    eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
 		eap_fast_deinit(sm, data);
 		return NULL;
 	}
@@ -1047,6 +1055,7 @@
 		}
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
 			   "- Provisioning completed successfully");
+		sm->expected_failure = 1;
 	} else {
 		/*
 		 * This is PAC refreshing, i.e., normal authentication that is
@@ -1244,6 +1253,7 @@
 				   "provisioning completed successfully.");
 			ret->methodState = METHOD_DONE;
 			ret->decision = DECISION_FAIL;
+			sm->expected_failure = 1;
 		} else {
 			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
 				   "completed successfully.");
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index 8c480b9..21d6098 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -330,6 +330,8 @@
 static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
 					    char *pos)
 {
+	if (!pos)
+		return "Cannot parse pac type";
 	pac->pac_type = atoi(pos);
 	if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
 	    pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 8a0644d..5b023c7 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-GPSK (RFC 5433)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, 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 @@
 	int specifier; /* CSuite/Specifier */
 	u8 *psk;
 	size_t psk_len;
+	u16 forced_cipher; /* force cipher or 0 to allow all supported */
 };
 
 
@@ -80,6 +81,7 @@
 	struct eap_gpsk_data *data;
 	const u8 *identity, *password;
 	size_t identity_len, password_len;
+	const char *phase1;
 
 	password = eap_get_config_password(sm, &password_len);
 	if (password == NULL) {
@@ -103,6 +105,18 @@
 		data->id_peer_len = identity_len;
 	}
 
+	phase1 = eap_get_config_phase1(sm);
+	if (phase1) {
+		const char *pos;
+
+		pos = os_strstr(phase1, "cipher=");
+		if (pos) {
+			data->forced_cipher = atoi(pos + 7);
+			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
+				   data->forced_cipher);
+		}
+	}
+
 	data->psk = os_malloc(password_len);
 	if (data->psk == NULL) {
 		eap_gpsk_deinit(sm, data);
@@ -195,7 +209,9 @@
 			   i, vendor, specifier);
 		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
 		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
-		    eap_gpsk_supported_ciphersuite(vendor, specifier)) {
+		    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
+		    (!data->forced_cipher || data->forced_cipher == specifier))
+		{
 			data->vendor = vendor;
 			data->specifier = specifier;
 		}
@@ -273,6 +289,7 @@
 	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
 					   &csuite_list_len, pos, end);
 	if (pos == NULL) {
+		ret->methodState = METHOD_DONE;
 		eap_gpsk_state(data, FAILURE);
 		return NULL;
 	}
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 62c867c..8288ba5 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -348,6 +348,10 @@
 
 	struct ext_password_data *ext_pw;
 	struct wpabuf *ext_pw_buf;
+
+	int external_sim;
+
+	unsigned int expected_failure:1;
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index 09a655e..2d7841d 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -1,6 +1,6 @@
 /*
  * EAP-IKEv2 peer (RFC 5106)
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -60,6 +60,7 @@
 	struct eap_ikev2_data *data;
 	const u8 *identity, *password;
 	size_t identity_len, password_len;
+	int fragment_size;
 
 	identity = eap_get_config_identity(sm, &identity_len);
 	if (identity == NULL) {
@@ -71,7 +72,11 @@
 	if (data == NULL)
 		return NULL;
 	data->state = WAIT_START;
-	data->fragment_size = IKEV2_FRAGMENT_SIZE;
+	fragment_size = eap_get_config_fragment_size(sm);
+	if (fragment_size <= 0)
+		data->fragment_size = IKEV2_FRAGMENT_SIZE;
+	else
+		data->fragment_size = fragment_size;
 	data->ikev2.state = SA_INIT;
 	data->ikev2.peer_auth = PEER_AUTH_SECRET;
 	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 3b93209..8634f75 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -22,7 +22,6 @@
 /* Maximum supported PEAP version
  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
  */
 #define EAP_PEAP_VERSION 1
 
@@ -315,8 +314,6 @@
 	len[1] = 1;
 
 	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
-	if (data->peap_version >= 2)
-		tlv_type |= EAP_TLV_TYPE_MANDATORY;
 	wpabuf_put_be16(buf, tlv_type);
 	wpabuf_put_be16(buf, 56);
 
@@ -580,33 +577,6 @@
 }
 
 
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(e, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(e, buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
 static int eap_peap_phase2_request(struct eap_sm *sm,
 				   struct eap_peap_data *data,
 				   struct eap_method_ret *ret,
@@ -837,49 +807,6 @@
 		in_decrypted = nmsg;
 	}
 
-	if (data->peap_version >= 2) {
-		struct eap_tlv_hdr *tlv;
-		struct wpabuf *nmsg;
-
-		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
-				   "EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		tlv = wpabuf_mhead(in_decrypted);
-		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
-		    EAP_TLV_EAP_PAYLOAD_TLV) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		if (sizeof(*tlv) + be_to_host16(tlv->length) >
-		    wpabuf_len(in_decrypted)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
-				   "length");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		hdr = (struct eap_hdr *) (tlv + 1);
-		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
-				   "EAP packet in EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-
-		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
-		if (nmsg == NULL) {
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-
-		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
-		wpabuf_free(in_decrypted);
-		in_decrypted = nmsg;
-	}
-
 	hdr = wpabuf_mhead(in_decrypted);
 	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
 		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
@@ -996,11 +923,6 @@
 		wpa_hexdump_buf_key(MSG_DEBUG,
 				    "EAP-PEAP: Encrypting Phase 2 data", resp);
 		/* PEAP version changes */
-		if (data->peap_version >= 2) {
-			resp = eap_peapv2_tlv_eap_payload(resp);
-			if (resp == NULL)
-				return -1;
-		}
 		if (wpabuf_len(resp) >= 5 &&
 		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
 		    eap_get_type(resp) == EAP_TYPE_TLV)
@@ -1091,7 +1013,7 @@
 			 * label, "client EAP encryption", instead. Use the old
 			 * label by default, but allow it to be configured with
 			 * phase1 parameter peaplabel=1. */
-			if (data->peap_version > 1 || data->force_new_label)
+			if (data->force_new_label)
 				label = "client PEAP encryption";
 			else
 				label = "client EAP encryption";
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
index 3b4dcef..23cdbe6 100644
--- a/src/eap_peer/eap_proxy.h
+++ b/src/eap_peer/eap_proxy.h
@@ -40,7 +40,8 @@
 int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
 			    int verbose);
 
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+		       size_t *imsi_len);
 
 int eap_proxy_notify_config(struct eap_proxy_sm *sm,
 			    struct eap_peer_config *config);
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index cd97fb6..d84f012 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -63,7 +63,8 @@
 }
 
 
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+		       size_t *imsi_len)
 {
 	return -1;
 }
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 267d0a5..fef4783 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -81,6 +81,7 @@
 	struct eap_pwd_data *data;
 	const u8 *identity, *password;
 	size_t identity_len, password_len;
+	int fragment_size;
 
 	password = eap_get_config_password(sm, &password_len);
 	if (password == NULL) {
@@ -127,7 +128,11 @@
 
 	data->out_frag_pos = data->in_frag_pos = 0;
 	data->inbuf = data->outbuf = NULL;
-	data->mtu = 1020; /* default from RFC 5931, make it configurable! */
+	fragment_size = eap_get_config_fragment_size(sm);
+	if (fragment_size <= 0)
+		data->mtu = 1020; /* default from RFC 5931 */
+	else
+		data->mtu = fragment_size;
 
 	data->state = PWD_ID_Req;
 
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 82ea18d..d856054 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -145,6 +145,80 @@
 }
 
 
+static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
+{
+	char req[200], *pos, *end;
+	size_t i;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
+	pos = req;
+	end = pos + sizeof(req);
+	pos += os_snprintf(pos, end - pos, "GSM-AUTH");
+	for (i = 0; i < data->num_chal; i++) {
+		pos += os_snprintf(pos, end - pos, ":");
+		pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
+					GSM_RAND_LEN);
+	}
+
+	eap_sm_request_sim(sm, req);
+	return 1;
+}
+
+
+static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
+				  struct eap_peer_config *conf)
+{
+	char *resp, *pos;
+	size_t i;
+
+	wpa_printf(MSG_DEBUG,
+		   "EAP-SIM: Use result from external SIM processing");
+
+	resp = conf->external_sim_resp;
+	conf->external_sim_resp = NULL;
+
+	if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
+		os_free(resp);
+		return -1;
+	}
+
+	pos = resp + 9;
+	for (i = 0; i < data->num_chal; i++) {
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
+			    data->rand[i], GSM_RAND_LEN);
+
+		if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
+				data->kc[i], EAP_SIM_KC_LEN);
+		pos += EAP_SIM_KC_LEN * 2;
+		if (*pos != ':')
+			goto invalid;
+		pos++;
+
+		if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
+			goto invalid;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
+				data->sres[i], EAP_SIM_SRES_LEN);
+		pos += EAP_SIM_SRES_LEN * 2;
+		if (i + 1 < data->num_chal) {
+			if (*pos != ':')
+				goto invalid;
+			pos++;
+		}
+	}
+
+	os_free(resp);
+	return 0;
+
+invalid:
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
+	os_free(resp);
+	return -1;
+}
+
+
 static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
 {
 	struct eap_peer_config *conf;
@@ -154,6 +228,14 @@
 	conf = eap_get_config(sm);
 	if (conf == NULL)
 		return -1;
+
+	if (sm->external_sim) {
+		if (conf->external_sim_resp)
+			return eap_sim_ext_sim_result(sm, data, conf);
+		else
+			return eap_sim_ext_sim_req(sm, data);
+	}
+
 	if (conf->pcsc) {
 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
 				   data->sres[0], data->kc[0]) ||
@@ -605,6 +687,7 @@
 	const u8 *identity;
 	size_t identity_len;
 	struct eap_sim_attrs eattr;
+	int res;
 
 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
 	data->reauth = 0;
@@ -648,8 +731,13 @@
 
 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
 	data->num_chal = attr->num_chal;
-		
-	if (eap_sim_gsm_auth(sm, data)) {
+
+	res = eap_sim_gsm_auth(sm, data);
+	if (res > 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
+		return NULL;
+	}
+	if (res) {
 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
 		return eap_sim_client_error(data, id,
 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index be8c301..b3a99b6 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -64,6 +64,14 @@
 		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
 	if (os_strstr(txt, "tls_disable_session_ticket=0"))
 		params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
+	if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
+		params->flags |= TLS_CONN_DISABLE_TLSv1_1;
+	if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
+		params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
+	if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
+		params->flags |= TLS_CONN_DISABLE_TLSv1_2;
+	if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
+		params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
 }
 
 
@@ -78,6 +86,7 @@
 	params->dh_file = (char *) config->dh_file;
 	params->subject_match = (char *) config->subject_match;
 	params->altsubject_match = (char *) config->altsubject_match;
+	params->suffix_match = config->domain_suffix_match;
 	params->engine = config->engine;
 	params->engine_id = config->engine_id;
 	params->pin = config->pin;
@@ -99,6 +108,7 @@
 	params->dh_file = (char *) config->dh_file2;
 	params->subject_match = (char *) config->subject_match2;
 	params->altsubject_match = (char *) config->altsubject_match2;
+	params->suffix_match = config->domain_suffix_match2;
 	params->engine = config->engine2;
 	params->engine_id = config->engine2_id;
 	params->pin = config->pin2;
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 8edb1ca..6bdd341 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -144,12 +144,13 @@
 	size_t identity_len;
 	int registrar;
 	struct wps_config cfg;
-	const char *pos;
+	const char *pos, *end;
 	const char *phase1;
 	struct wps_context *wps;
 	struct wps_credential new_ap_settings;
 	int res;
 	int nfc = 0;
+	u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN];
 
 	wps = sm->wps;
 	if (wps == NULL) {
@@ -209,6 +210,15 @@
 			cfg.pbc = 1;
 	}
 
+	pos = os_strstr(phase1, "dev_pw_id=");
+	if (pos) {
+		u16 id = atoi(pos + 10);
+		if (id == DEV_PW_NFC_CONNECTION_HANDOVER)
+			nfc = 1;
+		if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER)
+			cfg.dev_pw_id = id;
+	}
+
 	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
 		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
 			   "configuration data");
@@ -216,9 +226,23 @@
 		return NULL;
 	}
 
-	pos = os_strstr(phase1, "dev_pw_id=");
-	if (pos && cfg.pin)
-		cfg.dev_pw_id = atoi(pos + 10);
+	pos = os_strstr(phase1, " pkhash=");
+	if (pos) {
+		size_t len;
+		pos += 8;
+		end = os_strchr(pos, ' ');
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN ||
+		    hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) {
+			wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash");
+			os_free(data);
+			return NULL;
+		}
+		cfg.peer_pubkey_hash = pkhash;
+	}
 
 	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
 	if (res < 0) {
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index fcf4712..1ccc352 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -1257,6 +1257,7 @@
 			wpabuf_free(msg);
 			return NULL;
 		}
+		wpabuf_free(plain);
 		data->state = IKEV2_FAILED;
 	} else {
 		/* HDR, N */
diff --git a/src/eap_server/Makefile b/src/eap_server/Makefile
index 9c41962..adfd3df 100644
--- a/src/eap_server/Makefile
+++ b/src/eap_server/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 54b7533..233e272 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -343,6 +343,7 @@
 
 	SM_ENTRY(EAP, PROPOSE_METHOD);
 
+try_another_method:
 	type = eap_sm_Policy_getNextMethod(sm, &vendor);
 	if (vendor == EAP_VENDOR_IETF)
 		sm->currentMethod = type;
@@ -360,8 +361,14 @@
 				   "method %d", sm->currentMethod);
 			sm->m = NULL;
 			sm->currentMethod = EAP_TYPE_NONE;
+			goto try_another_method;
 		}
 	}
+	if (sm->m == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
+		sm->decision = DECISION_FAILURE;
+		return;
+	}
 	if (sm->currentMethod == EAP_TYPE_IDENTITY ||
 	    sm->currentMethod == EAP_TYPE_NOTIFICATION)
 		sm->methodState = METHOD_CONTINUE;
@@ -702,6 +709,15 @@
 			SM_ENTER(EAP, METHOD_RESPONSE);
 		break;
 	case EAP_METHOD_REQUEST:
+		if (sm->m == NULL) {
+			/*
+			 * This transition is not mentioned in RFC 4137, but it
+			 * is needed to handle cleanly a case where EAP method
+			 * initialization fails.
+			 */
+			SM_ENTER(EAP, FAILURE);
+			break;
+		}
 		SM_ENTER(EAP, SEND_REQUEST);
 		break;
 	case EAP_METHOD_RESPONSE:
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 469b9a0..46fc458 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1040,6 +1040,7 @@
 	data->auts_reported = 1;
 
 	/* Remain in CHALLENGE state to re-try after resynchronization */
+	eap_aka_fullauth(sm, data);
 }
 
 
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 68253c4..defcb3c 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -22,7 +22,6 @@
 /* Maximum supported PEAP version
  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
  */
 #define EAP_PEAP_VERSION 1
 
@@ -99,33 +98,6 @@
 }
 
 
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(e, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(e, buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
 static void eap_peap_req_success(struct eap_sm *sm,
 				 struct eap_peap_data *data)
 {
@@ -239,8 +211,6 @@
 		return NULL;
 	}
 	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
-	if (data->peap_version >= 2 && buf)
-		buf = eap_peapv2_tlv_eap_payload(buf);
 	if (buf == NULL)
 		return NULL;
 
@@ -425,8 +395,6 @@
 		len[1] = 1;
 
 		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
-		if (data->peap_version >= 2)
-			tlv_type |= EAP_TLV_TYPE_MANDATORY;
 		wpabuf_put_be16(buf, tlv_type);
 		wpabuf_put_be16(buf, 56);
 
@@ -505,8 +473,7 @@
 		return eap_peap_build_start(sm, data, id);
 	case PHASE1:
 	case PHASE1_ID2:
-		if (data->peap_version < 2 &&
-		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
 				   "starting Phase2");
 			eap_peap_state(data, PHASE2_START);
@@ -1079,47 +1046,6 @@
 		wpabuf_free(in_decrypted);
 
 		in_decrypted = nbuf;
-	} else if (data->peap_version >= 2) {
-		struct eap_tlv_hdr *tlv;
-		struct wpabuf *nmsg;
-
-		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
-				   "EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		tlv = wpabuf_mhead(in_decrypted);
-		if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
-		    EAP_TLV_EAP_PAYLOAD_TLV) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		if (sizeof(*tlv) + be_to_host16(tlv->length) >
-		    wpabuf_len(in_decrypted)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
-				   "length");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		hdr = (struct eap_hdr *) (tlv + 1);
-		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
-				   "EAP packet in EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-
-		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
-		if (nmsg == NULL) {
-			wpabuf_free(in_decrypted);
-			return;
-		}
-
-		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
-		wpabuf_free(in_decrypted);
-		in_decrypted = nmsg;
 	}
 
 	hdr = wpabuf_head(in_decrypted);
@@ -1168,53 +1094,6 @@
 }
 
 
-static int eap_peapv2_start_phase2(struct eap_sm *sm,
-				   struct eap_peap_data *data)
-{
-	struct wpabuf *buf, *buf2;
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
-		   "payload in the same message");
-	eap_peap_state(data, PHASE1_ID2);
-	if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
-		return -1;
-
-	/* TODO: which Id to use here? */
-	buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
-	if (buf == NULL)
-		return -1;
-
-	buf2 = eap_peapv2_tlv_eap_payload(buf);
-	if (buf2 == NULL)
-		return -1;
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
-
-	buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-				     buf2);
-	wpabuf_free(buf2);
-
-	if (buf == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
-			   "data");
-		return -1;
-	}
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
-			buf);
-
-	/* Append TLS data into the pending buffer after the Server Finished */
-	if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
-		wpabuf_free(buf);
-		return -1;
-	}
-	wpabuf_put_buf(data->ssl.tls_out, buf);
-	wpabuf_free(buf);
-
-	return 0;
-}
-
-
 static int eap_peap_process_version(struct eap_sm *sm, void *priv,
 				    int peer_version)
 {
@@ -1249,14 +1128,6 @@
 			eap_peap_state(data, FAILURE);
 			break;
 		}
-
-		if (data->peap_version >= 2 &&
-		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			if (eap_peapv2_start_phase2(sm, data)) {
-				eap_peap_state(data, FAILURE);
-				break;
-			}
-		}
 		break;
 	case PHASE2_START:
 		eap_peap_state(data, PHASE2_ID);
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 9efb5b2..526e1bc 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -33,6 +33,11 @@
 int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 			    int verify_peer)
 {
+	if (sm->ssl_ctx == NULL) {
+		wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
+		return -1;
+	}
+
 	data->eap = sm;
 	data->phase2 = sm->init_phase2;
 
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 1b9d701..bc2cbe5 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -38,7 +38,6 @@
 	char imsi[20];
 	enum { PENDING, SUCCESS, FAILURE } state;
 	void *cb_session_ctx;
-	struct os_time timestamp;
 	int aka;
 	union {
 		struct {
@@ -630,7 +629,7 @@
 
 	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (data->sock < 0) {
-		perror("socket(eap_sim_db)");
+		wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
 		return -1;
 	}
 
@@ -640,8 +639,13 @@
 		    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
 	os_free(data->local_sock);
 	data->local_sock = os_strdup(addr.sun_path);
+	if (data->local_sock == NULL) {
+		close(data->sock);
+		data->sock = -1;
+		return -1;
+	}
 	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(eap_sim_db)");
+		wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
 		close(data->sock);
 		data->sock = -1;
 		return -1;
@@ -651,12 +655,16 @@
 	addr.sun_family = AF_UNIX;
 	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
 	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("connect(eap_sim_db)");
+		wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
+			   strerror(errno));
 		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
 				  (u8 *) addr.sun_path,
 				  os_strlen(addr.sun_path));
 		close(data->sock);
 		data->sock = -1;
+		unlink(data->local_sock);
+		os_free(data->local_sock);
+		data->local_sock = NULL;
 		return -1;
 	}
 
@@ -804,7 +812,8 @@
 
 	if (send(data->sock, msg, len, 0) < 0) {
 		_errno = errno;
-		perror("send[EAP-SIM DB UNIX]");
+		wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+			   strerror(errno));
 	}
 
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
@@ -816,7 +825,8 @@
 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
 			   "external server");
 		if (send(data->sock, msg, len, 0) < 0) {
-			perror("send[EAP-SIM DB UNIX]");
+			wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+				   strerror(errno));
 			return -1;
 		}
 	}
@@ -932,7 +942,6 @@
 	if (entry == NULL)
 		return EAP_SIM_DB_FAILURE;
 
-	os_get_time(&entry->timestamp);
 	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
 	entry->cb_session_ctx = cb_session_ctx;
 	entry->state = PENDING;
@@ -1392,7 +1401,6 @@
 	if (entry == NULL)
 		return EAP_SIM_DB_FAILURE;
 
-	os_get_time(&entry->timestamp);
 	entry->aka = 1;
 	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
 	entry->cb_session_ctx = cb_session_ctx;
diff --git a/src/eapol_auth/Makefile b/src/eapol_auth/Makefile
index 9c41962..adfd3df 100644
--- a/src/eapol_auth/Makefile
+++ b/src/eapol_auth/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c
index b6e0b13..6c6969b 100644
--- a/src/eapol_auth/eapol_auth_dump.c
+++ b/src/eapol_auth/eapol_auth_dump.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.1X-2004 Authenticator - State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -118,108 +118,172 @@
 }
 
 
-void eapol_auth_dump_state(FILE *f, const char *prefix,
-			   struct eapol_state_machine *sm)
+int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf,
+			  size_t buflen)
 {
-	fprintf(f, "%sEAPOL state machine:\n", prefix);
-	fprintf(f, "%s  aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
-		sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+	char *pos, *end;
+	int ret;
+
+	pos = buf;
+	end = pos + buflen;
+
+	ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n"
+			  "reAuthWhen=%d\n",
+			  sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
 #define _SB(b) ((b) ? "TRUE" : "FALSE")
-	fprintf(f,
-		"%s  authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
-		"%s  authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
-		"%s  eapSuccess=%s eapTimeout=%s initialize=%s "
-		"keyAvailable=%s\n"
-		"%s  keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
-		"%s  portEnabled=%s portValid=%s reAuthenticate=%s\n",
-		prefix, _SB(sm->authAbort), _SB(sm->authFail),
-		port_state_txt(sm->authPortStatus), _SB(sm->authStart),
-		prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
-		_SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
-		prefix, _SB(sm->eap_if->eapSuccess),
-		_SB(sm->eap_if->eapTimeout),
-		_SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
-		prefix, _SB(sm->keyDone), _SB(sm->keyRun),
-		_SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
-		prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
-		_SB(sm->reAuthenticate));
+	ret = os_snprintf(pos, end - pos,
+			  "authAbort=%s\n"
+			  "authFail=%s\n"
+			  "authPortStatus=%s\n"
+			  "authStart=%s\n"
+			  "authTimeout=%s\n"
+			  "authSuccess=%s\n"
+			  "eapFail=%s\n"
+			  "eapolEap=%s\n"
+			  "eapSuccess=%s\n"
+			  "eapTimeout=%s\n"
+			  "initialize=%s\n"
+			  "keyAvailable=%s\n"
+			  "keyDone=%s\n"
+			  "keyRun=%s\n"
+			  "keyTxEnabled=%s\n"
+			  "portControl=%s\n"
+			  "portEnabled=%s\n"
+			  "portValid=%s\n"
+			  "reAuthenticate=%s\n",
+			  _SB(sm->authAbort),
+			  _SB(sm->authFail),
+			  port_state_txt(sm->authPortStatus),
+			  _SB(sm->authStart),
+			  _SB(sm->authTimeout),
+			  _SB(sm->authSuccess),
+			  _SB(sm->eap_if->eapFail),
+			  _SB(sm->eapolEap),
+			  _SB(sm->eap_if->eapSuccess),
+			  _SB(sm->eap_if->eapTimeout),
+			  _SB(sm->initialize),
+			  _SB(sm->eap_if->eapKeyAvailable),
+			  _SB(sm->keyDone), _SB(sm->keyRun),
+			  _SB(sm->keyTxEnabled),
+			  port_type_txt(sm->portControl),
+			  _SB(sm->eap_if->portEnabled),
+			  _SB(sm->portValid),
+			  _SB(sm->reAuthenticate));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Authenticator PAE:\n"
-		"%s    state=%s\n"
-		"%s    eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
-		"%s    portMode=%s reAuthCount=%d\n"
-		"%s    quietPeriod=%d reAuthMax=%d\n"
-		"%s    authEntersConnecting=%d\n"
-		"%s    authEapLogoffsWhileConnecting=%d\n"
-		"%s    authEntersAuthenticating=%d\n"
-		"%s    authAuthSuccessesWhileAuthenticating=%d\n"
-		"%s    authAuthTimeoutsWhileAuthenticating=%d\n"
-		"%s    authAuthFailWhileAuthenticating=%d\n"
-		"%s    authAuthEapStartsWhileAuthenticating=%d\n"
-		"%s    authAuthEapLogoffWhileAuthenticating=%d\n"
-		"%s    authAuthReauthsWhileAuthenticated=%d\n"
-		"%s    authAuthEapStartsWhileAuthenticated=%d\n"
-		"%s    authAuthEapLogoffWhileAuthenticated=%d\n",
-		prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
-		_SB(sm->eapolLogoff), _SB(sm->eapolStart),
-		_SB(sm->eap_if->eapRestart),
-		prefix, port_type_txt(sm->portMode), sm->reAuthCount,
-		prefix, sm->quietPeriod, sm->reAuthMax,
-		prefix, sm->authEntersConnecting,
-		prefix, sm->authEapLogoffsWhileConnecting,
-		prefix, sm->authEntersAuthenticating,
-		prefix, sm->authAuthSuccessesWhileAuthenticating,
-		prefix, sm->authAuthTimeoutsWhileAuthenticating,
-		prefix, sm->authAuthFailWhileAuthenticating,
-		prefix, sm->authAuthEapStartsWhileAuthenticating,
-		prefix, sm->authAuthEapLogoffWhileAuthenticating,
-		prefix, sm->authAuthReauthsWhileAuthenticated,
-		prefix, sm->authAuthEapStartsWhileAuthenticated,
-		prefix, sm->authAuthEapLogoffWhileAuthenticated);
+	ret = os_snprintf(pos, end - pos,
+			  "auth_pae_state=%s\n"
+			  "eapolLogoff=%s\n"
+			  "eapolStart=%s\n"
+			  "eapRestart=%s\n"
+			  "portMode=%s\n"
+			  "reAuthCount=%d\n"
+			  "quietPeriod=%d\n"
+			  "reAuthMax=%d\n"
+			  "authEntersConnecting=%d\n"
+			  "authEapLogoffsWhileConnecting=%d\n"
+			  "authEntersAuthenticating=%d\n"
+			  "authAuthSuccessesWhileAuthenticating=%d\n"
+			  "authAuthTimeoutsWhileAuthenticating=%d\n"
+			  "authAuthFailWhileAuthenticating=%d\n"
+			  "authAuthEapStartsWhileAuthenticating=%d\n"
+			  "authAuthEapLogoffWhileAuthenticating=%d\n"
+			  "authAuthReauthsWhileAuthenticated=%d\n"
+			  "authAuthEapStartsWhileAuthenticated=%d\n"
+			  "authAuthEapLogoffWhileAuthenticated=%d\n",
+			  auth_pae_state_txt(sm->auth_pae_state),
+			  _SB(sm->eapolLogoff),
+			  _SB(sm->eapolStart),
+			  _SB(sm->eap_if->eapRestart),
+			  port_type_txt(sm->portMode),
+			  sm->reAuthCount,
+			  sm->quietPeriod, sm->reAuthMax,
+			  sm->authEntersConnecting,
+			  sm->authEapLogoffsWhileConnecting,
+			  sm->authEntersAuthenticating,
+			  sm->authAuthSuccessesWhileAuthenticating,
+			  sm->authAuthTimeoutsWhileAuthenticating,
+			  sm->authAuthFailWhileAuthenticating,
+			  sm->authAuthEapStartsWhileAuthenticating,
+			  sm->authAuthEapLogoffWhileAuthenticating,
+			  sm->authAuthReauthsWhileAuthenticated,
+			  sm->authAuthEapStartsWhileAuthenticated,
+			  sm->authAuthEapLogoffWhileAuthenticated);
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Backend Authentication:\n"
-		"%s    state=%s\n"
-		"%s    eapNoReq=%s eapReq=%s eapResp=%s\n"
-		"%s    serverTimeout=%d\n"
-		"%s    backendResponses=%d\n"
-		"%s    backendAccessChallenges=%d\n"
-		"%s    backendOtherRequestsToSupplicant=%d\n"
-		"%s    backendAuthSuccesses=%d\n"
-		"%s    backendAuthFails=%d\n",
-		prefix, prefix,
-		be_auth_state_txt(sm->be_auth_state),
-		prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
-		_SB(sm->eap_if->eapResp),
-		prefix, sm->serverTimeout,
-		prefix, sm->backendResponses,
-		prefix, sm->backendAccessChallenges,
-		prefix, sm->backendOtherRequestsToSupplicant,
-		prefix, sm->backendAuthSuccesses,
-		prefix, sm->backendAuthFails);
+	ret = os_snprintf(pos, end - pos,
+			  "be_auth_state=%s\n"
+			  "eapNoReq=%s\n"
+			  "eapReq=%s\n"
+			  "eapResp=%s\n"
+			  "serverTimeout=%d\n"
+			  "backendResponses=%d\n"
+			  "backendAccessChallenges=%d\n"
+			  "backendOtherRequestsToSupplicant=%d\n"
+			  "backendAuthSuccesses=%d\n"
+			  "backendAuthFails=%d\n",
+			  be_auth_state_txt(sm->be_auth_state),
+			  _SB(sm->eap_if->eapNoReq),
+			  _SB(sm->eap_if->eapReq),
+			  _SB(sm->eap_if->eapResp),
+			  sm->serverTimeout,
+			  sm->backendResponses,
+			  sm->backendAccessChallenges,
+			  sm->backendOtherRequestsToSupplicant,
+			  sm->backendAuthSuccesses,
+			  sm->backendAuthFails);
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Reauthentication Timer:\n"
-		"%s    state=%s\n"
-		"%s    reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
-		reauth_timer_state_txt(sm->reauth_timer_state), prefix,
-		sm->reAuthPeriod, _SB(sm->reAuthEnabled));
+	ret = os_snprintf(pos, end - pos,
+			  "reauth_timer_state=%s\n"
+			  "reAuthPeriod=%d\n"
+			  "reAuthEnabled=%s\n",
+			  reauth_timer_state_txt(sm->reauth_timer_state),
+			  sm->reAuthPeriod,
+			  _SB(sm->reAuthEnabled));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Authenticator Key Transmit:\n"
-		"%s    state=%s\n", prefix, prefix,
-		auth_key_tx_state_txt(sm->auth_key_tx_state));
+	ret = os_snprintf(pos, end - pos,
+			  "auth_key_tx_state=%s\n",
+			  auth_key_tx_state_txt(sm->auth_key_tx_state));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Key Receive:\n"
-		"%s    state=%s\n"
-		"%s    rxKey=%s\n", prefix, prefix,
-		key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
+	ret = os_snprintf(pos, end - pos,
+			  "key_rx_state=%s\n"
+			  "rxKey=%s\n",
+			  key_rx_state_txt(sm->key_rx_state),
+			  _SB(sm->rxKey));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 
-	fprintf(f, "%s  Controlled Directions:\n"
-		"%s    state=%s\n"
-		"%s    adminControlledDirections=%s "
-		"operControlledDirections=%s\n"
-		"%s    operEdge=%s\n", prefix, prefix,
-		ctrl_dir_state_txt(sm->ctrl_dir_state),
-		prefix, ctrl_dir_txt(sm->adminControlledDirections),
-		ctrl_dir_txt(sm->operControlledDirections),
-		prefix, _SB(sm->operEdge));
+	ret = os_snprintf(pos, end - pos,
+			  "ctrl_dir_state=%s\n"
+			  "adminControlledDirections=%s\n"
+			  "operControlledDirections=%s\n"
+			  "operEdge=%s\n",
+			  ctrl_dir_state_txt(sm->ctrl_dir_state),
+			  ctrl_dir_txt(sm->adminControlledDirections),
+			  ctrl_dir_txt(sm->operControlledDirections),
+			  _SB(sm->operEdge));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
 #undef _SB
+
+	return pos - buf;
 }
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 013d781..a257781 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1062,6 +1062,10 @@
 	}
 	if (src->pac_opaque_encr_key) {
 		dst->pac_opaque_encr_key = os_malloc(16);
+		if (dst->pac_opaque_encr_key == NULL) {
+			os_free(dst->eap_req_id_text);
+			return -1;
+		}
 		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
 			  16);
 	} else
@@ -1070,6 +1074,7 @@
 		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
 		if (dst->eap_fast_a_id == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			return -1;
 		}
 		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
@@ -1081,6 +1086,7 @@
 		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
 		if (dst->eap_fast_a_id_info == NULL) {
 			os_free(dst->eap_req_id_text);
+			os_free(dst->pac_opaque_encr_key);
 			os_free(dst->eap_fast_a_id);
 			return -1;
 		}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 3a0f450..f0ff464 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -83,8 +83,8 @@
 		 const char *identity, const char *radius_cui);
 void eapol_auth_free(struct eapol_state_machine *sm);
 void eapol_auth_step(struct eapol_state_machine *sm);
-void eapol_auth_dump_state(FILE *f, const char *prefix,
-			   struct eapol_state_machine *sm);
+int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf,
+			  size_t buflen);
 int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
 
 #endif /* EAPOL_AUTH_SM_H */
diff --git a/src/eapol_supp/Makefile b/src/eapol_supp/Makefile
index 9c41962..adfd3df 100644
--- a/src/eapol_supp/Makefile
+++ b/src/eapol_supp/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 9b054fc..cbcde7e 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -137,6 +137,9 @@
 	Boolean cached_pmk;
 
 	Boolean unicast_key_received, broadcast_key_received;
+
+	Boolean force_authorized_update;
+
 #ifdef CONFIG_EAP_PROXY
 	Boolean use_eap_proxy;
 	struct eap_proxy_sm *eap_proxy;
@@ -210,7 +213,6 @@
 	SM_ENTRY(SUPP_PAE, LOGOFF);
 	eapol_sm_txLogoff(sm);
 	sm->logoffSent = TRUE;
-	sm->suppPortStatus = Unauthorized;
 	eapol_sm_set_port_unauthorized(sm);
 }
 
@@ -221,7 +223,6 @@
 	sm->sPortMode = Auto;
 	sm->startCount = 0;
 	sm->logoffSent = FALSE;
-	sm->suppPortStatus = Unauthorized;
 	eapol_sm_set_port_unauthorized(sm);
 	sm->suppAbort = TRUE;
 
@@ -286,7 +287,6 @@
 	SM_ENTRY(SUPP_PAE, HELD);
 	sm->heldWhile = sm->heldPeriod;
 	eapol_enable_timer_tick(sm);
-	sm->suppPortStatus = Unauthorized;
 	eapol_sm_set_port_unauthorized(sm);
 	sm->cb_status = EAPOL_CB_FAILURE;
 }
@@ -295,7 +295,6 @@
 SM_STATE(SUPP_PAE, AUTHENTICATED)
 {
 	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
-	sm->suppPortStatus = Authorized;
 	eapol_sm_set_port_authorized(sm);
 	sm->cb_status = EAPOL_CB_SUCCESS;
 }
@@ -311,7 +310,6 @@
 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
 {
 	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
-	sm->suppPortStatus = Authorized;
 	eapol_sm_set_port_authorized(sm);
 	sm->sPortMode = ForceAuthorized;
 }
@@ -320,7 +318,6 @@
 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
 {
 	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
-	sm->suppPortStatus = Unauthorized;
 	eapol_sm_set_port_unauthorized(sm);
 	sm->sPortMode = ForceUnauthorized;
 	eapol_sm_txLogoff(sm);
@@ -879,14 +876,24 @@
 
 static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
 {
-	if (sm->ctx->port_cb)
+	int cb;
+
+	cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
+	sm->force_authorized_update = FALSE;
+	sm->suppPortStatus = Authorized;
+	if (cb && sm->ctx->port_cb)
 		sm->ctx->port_cb(sm->ctx->ctx, 1);
 }
 
 
 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
 {
-	if (sm->ctx->port_cb)
+	int cb;
+
+	cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
+	sm->force_authorized_update = FALSE;
+	sm->suppPortStatus = Unauthorized;
+	if (cb && sm->ctx->port_cb)
 		sm->ctx->port_cb(sm->ctx->ctx, 0);
 }
 
@@ -933,9 +940,15 @@
 	}
 
 	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
-		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+		enum eapol_supp_result result;
+		if (sm->cb_status == EAPOL_CB_SUCCESS)
+			result = EAPOL_SUPP_RESULT_SUCCESS;
+		else if (eap_peer_was_failure_expected(sm->eap))
+			result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+		else
+			result = EAPOL_SUPP_RESULT_FAILURE;
 		sm->cb_status = EAPOL_CB_IN_PROGRESS;
-		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+		sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
 	}
 }
 
@@ -1257,6 +1270,24 @@
 
 	switch (hdr->type) {
 	case IEEE802_1X_TYPE_EAP_PACKET:
+		if (sm->conf.workaround) {
+			/*
+			 * An AP has been reported to send out EAP message with
+			 * undocumented code 10 at some point near the
+			 * completion of EAP authentication. This can result in
+			 * issues with the unexpected EAP message triggering
+			 * restart of EAPOL authentication. Avoid this by
+			 * skipping the message without advancing the state
+			 * machine.
+			 */
+			const struct eap_hdr *ehdr =
+				(const struct eap_hdr *) (hdr + 1);
+			if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
+				wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
+				break;
+			}
+		}
+
 		if (sm->cached_pmk) {
 			/* Trying to use PMKSA caching, but Authenticator did
 			 * not seem to have a matching entry. Need to restart
@@ -1352,6 +1383,8 @@
 		return;
 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 		   "portEnabled=%d", enabled);
+	if (sm->portEnabled != enabled)
+		sm->force_authorized_update = TRUE;
 	sm->portEnabled = enabled;
 	eapol_sm_step(sm);
 }
@@ -1461,6 +1494,7 @@
 		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
 		eap_set_workaround(sm->eap, conf->workaround);
 		eap_set_force_disabled(sm->eap, conf->eap_disabled);
+		eap_set_external_sim(sm->eap, conf->external_sim);
 	}
 }
 
@@ -1589,7 +1623,6 @@
 		return;
 	sm->cached_pmk = FALSE;
 	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
-	sm->suppPortStatus = Unauthorized;
 	eapol_sm_set_port_unauthorized(sm);
 
 	/* Make sure we do not start sending EAPOL-Start frames first, but
@@ -1983,6 +2016,7 @@
 #endif /* CONFIG_EAP_PROXY */
 
 	/* Initialize EAPOL state machines */
+	sm->force_authorized_update = TRUE;
 	sm->initialize = TRUE;
 	eapol_sm_step(sm);
 	sm->initialize = FALSE;
@@ -2032,3 +2066,15 @@
 		return 0;
 	return !sm->eapSuccess && sm->eapFail;
 }
+
+
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
+{
+#ifdef CONFIG_EAP_PROXY
+	if (sm->eap_proxy == NULL)
+		return -1;
+	return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
+#else /* CONFIG_EAP_PROXY */
+	return -1;
+#endif /* CONFIG_EAP_PROXY */
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index c4b87da..934eda0 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -53,11 +53,22 @@
 	 * eap_disabled - Whether EAP is disabled
 	 */
 	int eap_disabled;
+
+	/**
+	 * external_sim - Use external processing for SIM/USIM operations
+	 */
+	int external_sim;
 };
 
 struct eapol_sm;
 struct wpa_config_blob;
 
+enum eapol_supp_result {
+	EAPOL_SUPP_RESULT_FAILURE,
+	EAPOL_SUPP_RESULT_SUCCESS,
+	EAPOL_SUPP_RESULT_EXPECTED_FAILURE
+};
+
 /**
  * struct eapol_ctx - Global (for all networks) EAPOL state machine context
  */
@@ -78,7 +89,7 @@
 	/**
 	 * cb - Function to be called when EAPOL negotiation has been completed
 	 * @eapol: Pointer to EAPOL state machine data
-	 * @success: Whether the authentication was completed successfully
+	 * @result: Whether the authentication was completed successfully
 	 * @ctx: Pointer to context data (cb_ctx)
 	 *
 	 * This optional callback function will be called when the EAPOL
@@ -86,7 +97,8 @@
 	 * EAPOL state machine to process the key and terminate the EAPOL state
 	 * machine. Currently, this is used only in RSN pre-authentication.
 	 */
-	void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
+	void (*cb)(struct eapol_sm *eapol, enum eapol_supp_result result,
+		   void *ctx);
 
 	/**
 	 * cb_ctx - Callback context for cb()
@@ -287,6 +299,7 @@
 void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
 			     struct ext_password_data *ext);
 int eapol_sm_failed(struct eapol_sm *sm);
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
 #else /* IEEE8021X_EAPOL */
 static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
 {
diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile
index 9c41962..adfd3df 100644
--- a/src/l2_packet/Makefile
+++ b/src/l2_packet/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
index cffba62..adfd3df 100644
--- a/src/p2p/Makefile
+++ b/src/p2p/Makefile
@@ -2,8 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	for d in $(SUBDIRS); do make -C $$d clean; done
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 738436c..6f3cd68 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -41,51 +41,32 @@
  * P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer
  * entries will be removed
  */
-#ifdef ANDROID_P2P
-#define P2P_PEER_EXPIRATION_AGE 30
-#else
-#define P2P_PEER_EXPIRATION_AGE 300
-#endif
+#ifndef P2P_PEER_EXPIRATION_AGE
+#define P2P_PEER_EXPIRATION_AGE 60
+#endif /* P2P_PEER_EXPIRATION_AGE */
 
 #define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2)
 
-#ifdef ANDROID_P2P
-int p2p_connection_in_progress(struct p2p_data *p2p)
-{
-	int ret = 0;
-
-	switch (p2p->state) {
-		case P2P_CONNECT:
-		case P2P_CONNECT_LISTEN:
-		case P2P_GO_NEG:
-		case P2P_WAIT_PEER_CONNECT:
-		case P2P_WAIT_PEER_IDLE:
-		case P2P_PROVISIONING:
-		case P2P_INVITE:
-		case P2P_INVITE_LISTEN:
-			ret = 1;
-			break;
-
-		default:
-			wpa_printf(MSG_DEBUG, "p2p_connection_in_progress state %d", p2p->state);
-			ret = 0;
-	}
-
-	return ret;
-}
-#endif
-
 static void p2p_expire_peers(struct p2p_data *p2p)
 {
 	struct p2p_device *dev, *n;
-	struct os_time now;
+	struct os_reltime now;
 	size_t i;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
 		if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec)
 			continue;
 
+		if (dev == p2p->go_neg_peer) {
+			/*
+			 * GO Negotiation is in progress with the peer, so
+			 * don't expire the peer entry until GO Negotiation
+			 * fails or times out.
+			 */
+			continue;
+		}
+
 		if (p2p->cfg->go_connected &&
 		    p2p->cfg->go_connected(p2p->cfg->cb_ctx,
 					   dev->info.p2p_device_addr)) {
@@ -93,7 +74,7 @@
 			 * We are connected as a client to a group in which the
 			 * peer is the GO, so do not expire the peer entry.
 			 */
-			os_get_time(&dev->last_seen);
+			os_get_reltime(&dev->last_seen);
 			continue;
 		}
 
@@ -107,25 +88,12 @@
 			 * The peer is connected as a client in a group where
 			 * we are the GO, so do not expire the peer entry.
 			 */
-			os_get_time(&dev->last_seen);
+			os_get_reltime(&dev->last_seen);
 			continue;
 		}
 
-#ifdef ANDROID_P2P
-		/* If Connection is in progress, don't expire the peer
-		*/
-		if (p2p_connection_in_progress(p2p))
-			continue;
-#endif
-
 		p2p_dbg(p2p, "Expiring old peer entry " MACSTR,
 			MAC2STR(dev->info.p2p_device_addr));
-
-#ifdef ANDROID_P2P
-		/* SD_FAIR_POLICY: Update the current sd_dev_list pointer to next device */
-		if(&dev->list == p2p->sd_dev_list)
-			p2p->sd_dev_list = dev->list.next;
-#endif
 		dl_list_del(&dev->list);
 		p2p_device_free(p2p, dev);
 	}
@@ -170,10 +138,6 @@
 		return "INVITE";
 	case P2P_INVITE_LISTEN:
 		return "INVITE_LISTEN";
-	case P2P_SEARCH_WHEN_READY:
-		return "SEARCH_WHEN_READY";
-	case P2P_CONTINUE_SEARCH_WHEN_READY:
-		return "CONTINUE_SEARCH_WHEN_READY";
 	default:
 		return "?";
 	}
@@ -247,6 +211,7 @@
 	if (p2p->go_neg_peer) {
 		p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
 		p2p->go_neg_peer->wps_method = WPS_NOT_READY;
+		p2p->go_neg_peer->oob_pw_id = 0;
 	}
 	p2p->go_neg_peer = NULL;
 
@@ -420,16 +385,11 @@
 	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
 		count++;
 		if (oldest == NULL ||
-		    os_time_before(&dev->last_seen, &oldest->last_seen))
+		    os_reltime_before(&dev->last_seen, &oldest->last_seen))
 			oldest = dev;
 	}
 	if (count + 1 > p2p->cfg->max_peers && oldest) {
 		p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
-#ifdef ANDROID_P2P
-		/* SD_FAIR_POLICY: Update the current sd_dev_list pointer to next device */
-		if(&oldest->list == p2p->sd_dev_list)
-			p2p->sd_dev_list = oldest->list.next;
-#endif
 		dl_list_del(&oldest->list);
 		p2p_device_free(p2p, oldest);
 	}
@@ -528,7 +488,7 @@
 
 		os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
 			  ETH_ALEN);
-		os_get_time(&dev->last_seen);
+		os_get_reltime(&dev->last_seen);
 		os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
 		os_memcpy(dev->member_in_go_iface, go_interface_addr,
 			  ETH_ALEN);
@@ -644,14 +604,14 @@
  * Info attributes.
  */
 int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
-		   struct os_time *rx_time, int level, const u8 *ies,
+		   struct os_reltime *rx_time, int level, const u8 *ies,
 		   size_t ies_len, int scan_res)
 {
 	struct p2p_device *dev;
 	struct p2p_message msg;
 	const u8 *p2p_dev_addr;
 	int i;
-	struct os_time time_now;
+	struct os_reltime time_now;
 
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -685,7 +645,7 @@
 	}
 
 	if (rx_time == NULL) {
-		os_get_time(&time_now);
+		os_get_reltime(&time_now);
 		rx_time = &time_now;
 	}
 
@@ -694,7 +654,7 @@
 	 * entry is newer than the one previously stored.
 	 */
 	if (dev->last_seen.sec > 0 &&
-	    os_time_before(rx_time, &dev->last_seen)) {
+	    os_reltime_before(rx_time, &dev->last_seen)) {
 		p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
 			(unsigned int) rx_time->sec,
 			(unsigned int) rx_time->usec,
@@ -704,7 +664,7 @@
 		return -1;
 	}
 
-	os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time));
+	os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
 
 	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
 
@@ -773,9 +733,6 @@
 
 	p2p_parse_free(&msg);
 
-	if (p2p_pending_sd_req(p2p, dev))
-		dev->flags |= P2P_DEV_SD_SCHEDULE;
-
 	if (dev->flags & P2P_DEV_REPORTED)
 		return 0;
 
@@ -932,9 +889,6 @@
 	if (res < 0) {
 		p2p_dbg(p2p, "Scan request failed");
 		p2p_continue_find(p2p);
-	} else if (res == 1) {
-		p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes");
-		p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
 	} else {
 		p2p_dbg(p2p, "Running p2p_scan");
 		p2p->p2p_scan_running = 1;
@@ -971,15 +925,7 @@
 				      p2p->after_scan_tx->wait_time);
 		os_free(p2p->after_scan_tx);
 		p2p->after_scan_tx = NULL;
-#ifdef ANDROID_P2P
-		/* For SD frames, there is a scenario, where we can receive a SD request frame during p2p_scan.
-		 * At that moment, we will send the SD response from this context. After sending the SD response,
-		 * we need to continue p2p_find. But if we return 1 from here, p2p_find is going to be stopped.
-		 */
-		return 0;
-#else
 		return 1;
-#endif
 	}
 
 	op = p2p->start_after_scan;
@@ -1038,7 +984,7 @@
 	int res;
 
 	p2p_dbg(p2p, "Starting find (type=%d)", type);
-	os_get_time(&p2p->find_start);
+	os_get_reltime(&p2p->find_start);
 	if (p2p->p2p_scan_running) {
 		p2p_dbg(p2p, "p2p_scan is already running");
 	}
@@ -1097,11 +1043,10 @@
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
 				       p2p, NULL);
-	} else if (res == 1) {
-		p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes");
-		res = 0;
-		p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
-		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+	} else if (p2p->p2p_scan_running) {
+		p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
+		/* wait for the previous p2p_scan to complete */
+		res = 0; /* do not report failure */
 	} else {
 		p2p_dbg(p2p, "Failed to start p2p_scan");
 		p2p_set_state(p2p, P2P_IDLE);
@@ -1111,47 +1056,13 @@
 	return res;
 }
 
-#ifdef ANDROID_P2P
-int p2p_search_pending(struct p2p_data *p2p)
-{
-	if(p2p == NULL)
-		return 0;
-
-	if(p2p->state == P2P_SEARCH_WHEN_READY)
-		return 1;
-
-	return 0;
-}
-#endif
-
-int p2p_other_scan_completed(struct p2p_data *p2p)
-{
-	if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
-		p2p_set_state(p2p, P2P_SEARCH);
-		p2p_search(p2p);
-		return 1;
-	}
-	if (p2p->state != P2P_SEARCH_WHEN_READY)
-		return 0;
-	p2p_dbg(p2p, "Starting pending P2P find now that previous scan was completed");
-	if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
-		     p2p->num_req_dev_types, p2p->req_dev_types,
-		     p2p->find_dev_id, p2p->search_delay) < 0) {
-		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
-		return 0;
-	}
-	return 1;
-}
-
 
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
 	p2p_dbg(p2p, "Stopping find");
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	p2p_clear_timeout(p2p);
-	if (p2p->state == P2P_SEARCH ||
-	    p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
-	    p2p->state == P2P_SEARCH_WHEN_READY)
+	if (p2p->state == P2P_SEARCH)
 		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
 	p2p_set_state(p2p, P2P_IDLE);
 	p2p_free_req_dev_types(p2p);
@@ -1208,19 +1119,21 @@
 
 static int p2p_prepare_channel_pref(struct p2p_data *p2p,
 				    unsigned int force_freq,
-				    unsigned int pref_freq)
+				    unsigned int pref_freq, int go)
 {
 	u8 op_class, op_channel;
 	unsigned int freq = force_freq ? force_freq : pref_freq;
 
-	p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
-		force_freq, pref_freq);
+	p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+		force_freq, pref_freq, go);
 	if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
 		p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
 		return -1;
 	}
 
-	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+	    (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+					  op_channel))) {
 		p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
 			freq, op_class, op_channel);
 		return -1;
@@ -1246,6 +1159,9 @@
 static void p2p_prepare_channel_best(struct p2p_data *p2p)
 {
 	u8 op_class, op_channel;
+	const int op_classes_5ghz[] = { 124, 115, 0 };
+	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+	const int op_classes_vht[] = { 128, 0 };
 
 	p2p_dbg(p2p, "Prepare channel best");
 
@@ -1277,6 +1193,21 @@
 		p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
 		p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
 		p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
+	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz,
+				      &p2p->op_reg_class, &p2p->op_channel) ==
+		   0) {
+		p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference",
+			p2p->op_reg_class, p2p->op_channel);
 	} else {
 		p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
 		p2p->op_reg_class = p2p->cfg->op_reg_class;
@@ -1294,6 +1225,7 @@
  * @dev: Selected peer device
  * @force_freq: Forced frequency in MHz or 0 if not forced
  * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
  * Returns: 0 on success, -1 on failure (channel not supported for P2P)
  *
  * This function is used to do initial operating channel selection for GO
@@ -1302,16 +1234,25 @@
  * is available.
  */
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-			unsigned int force_freq, unsigned int pref_freq)
+			unsigned int force_freq, unsigned int pref_freq, int go)
 {
-	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
-		force_freq, pref_freq);
+	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+		force_freq, pref_freq, go);
 	if (force_freq || pref_freq) {
-		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+		    0)
 			return -1;
 	} else {
 		p2p_prepare_channel_best(p2p);
 	}
+	p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+	if (go)
+		p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+	else if (!force_freq)
+		p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
+				   &p2p->channels);
+	p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
 	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
 		p2p->op_reg_class, p2p->op_channel,
 		force_freq ? " (forced)" : "");
@@ -1350,15 +1291,16 @@
 		int go_intent, const u8 *own_interface_addr,
 		unsigned int force_freq, int persistent_group,
 		const u8 *force_ssid, size_t force_ssid_len,
-		int pd_before_go_neg, unsigned int pref_freq)
+		int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
 {
 	struct p2p_device *dev;
 
 	p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
 		"  GO Intent=%d  Intended Interface Address=" MACSTR
-		" wps_method=%d persistent_group=%d pd_before_go_neg=%d",
+		" wps_method=%d persistent_group=%d pd_before_go_neg=%d "
+		"oob_pw_id=%u",
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
-		wps_method, persistent_group, pd_before_go_neg);
+		wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
 
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
@@ -1367,7 +1309,8 @@
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+				go_intent == 15) < 0)
 		return -1;
 
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
@@ -1441,6 +1384,7 @@
 	}
 
 	dev->wps_method = wps_method;
+	dev->oob_pw_id = oob_pw_id;
 	dev->status = P2P_SC_SUCCESS;
 
 	if (p2p->p2p_scan_running) {
@@ -1460,15 +1404,15 @@
 		  int go_intent, const u8 *own_interface_addr,
 		  unsigned int force_freq, int persistent_group,
 		  const u8 *force_ssid, size_t force_ssid_len,
-		  unsigned int pref_freq)
+		  unsigned int pref_freq, u16 oob_pw_id)
 {
 	struct p2p_device *dev;
 
 	p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
 		"  GO Intent=%d  Intended Interface Address=" MACSTR
-		" wps_method=%d  persistent_group=%d",
+		" wps_method=%d  persistent_group=%d oob_pw_id=%u",
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
-		wps_method, persistent_group);
+		wps_method, persistent_group, oob_pw_id);
 
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL) {
@@ -1477,7 +1421,8 @@
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+				15) < 0)
 		return -1;
 
 	p2p->ssid_set = 0;
@@ -1498,6 +1443,7 @@
 	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
 
 	dev->wps_method = wps_method;
+	dev->oob_pw_id = oob_pw_id;
 	dev->status = P2P_SC_SUCCESS;
 
 	return 0;
@@ -1507,7 +1453,7 @@
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
 		      struct p2p_device *dev, struct p2p_message *msg)
 {
-	os_get_time(&dev->last_seen);
+	os_get_reltime(&dev->last_seen);
 
 	p2p_copy_wps_info(p2p, dev, 0, msg);
 
@@ -1618,8 +1564,15 @@
 		}
 	}
 
+	p2p_channels_dump(p2p, "own channels", &p2p->channels);
+	p2p_channels_dump(p2p, "peer channels", &peer->channels);
 	p2p_channels_intersect(&p2p->channels, &peer->channels,
 			       &intersection);
+	if (go) {
+		p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+		p2p_channels_dump(p2p, "intersection after no-GO removal",
+				  &intersection);
+	}
 	freqs = 0;
 	for (i = 0; i < intersection.reg_classes; i++) {
 		struct p2p_reg_class *c = &intersection.reg_class[i];
@@ -1642,6 +1595,7 @@
 	p2p->ssid_set = 0;
 	peer->go_neg_req_sent = 0;
 	peer->wps_method = WPS_NOT_READY;
+	peer->oob_pw_id = 0;
 
 	p2p_set_state(p2p, P2P_PROVISIONING);
 	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -1672,6 +1626,7 @@
 					   rx_freq);
 		break;
 	case P2P_INVITATION_RESP:
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
 		break;
 	case P2P_PROV_DISC_REQ:
@@ -1805,7 +1760,8 @@
 	if (p2p->invite_peer == NULL)
 		return;
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
-	p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr);
+	p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+			p2p->invite_dev_pw_id);
 }
 
 
@@ -1838,7 +1794,7 @@
 	if (dev) {
 		if (dev->country[0] == 0 && msg.listen_channel)
 			os_memcpy(dev->country, msg.listen_channel, 3);
-		os_get_time(&dev->last_seen);
+		os_get_reltime(&dev->last_seen);
 		p2p_parse_free(&msg);
 		return; /* already known */
 	}
@@ -1849,7 +1805,7 @@
 		return;
 	}
 
-	os_get_time(&dev->last_seen);
+	os_get_reltime(&dev->last_seen);
 	dev->flags |= P2P_DEV_PROBE_REQ_ONLY;
 
 	if (msg.listen_channel) {
@@ -1883,7 +1839,7 @@
 
 	dev = p2p_get_device(p2p, addr);
 	if (dev) {
-		os_get_time(&dev->last_seen);
+		os_get_reltime(&dev->last_seen);
 		return dev; /* already known */
 	}
 
@@ -1978,7 +1934,11 @@
 		pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
 	}
 
-	p2p_build_wps_ie(p2p, buf, pw_id, 1);
+	if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_probe_resp)
@@ -2011,17 +1971,21 @@
 
 	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 */
+		p2p_dbg(p2p, "Could not parse Probe Request frame - ignore it");
 		return P2P_PREQ_MALFORMED;
 	}
 
 	if (elems.p2p == NULL) {
 		/* not a P2P probe - ignore it */
+		p2p_dbg(p2p, "Not a P2P probe - ignore it");
 		return P2P_PREQ_NOT_P2P;
 	}
 
@@ -2029,11 +1993,15 @@
 	    os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
 		/* Not sent to the broadcast address or our P2P Device Address
 		 */
+		p2p_dbg(p2p, "Probe Req DA " MACSTR " not ours - ignore it",
+			MAC2STR(dst));
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
 	if (bssid && !is_broadcast_ether_addr(bssid)) {
 		/* Not sent to the Wildcard BSSID */
+		p2p_dbg(p2p, "Probe Req BSSID " MACSTR " not wildcard - ignore it",
+			MAC2STR(bssid));
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
@@ -2041,23 +2009,28 @@
 	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
 	    0) {
 		/* not using P2P Wildcard SSID - ignore */
+		p2p_dbg(p2p, "Probe Req not using P2P Wildcard SSID - ignore it");
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
 	if (supp_rates_11b_only(&elems)) {
 		/* Indicates support for 11b rates only */
+		p2p_dbg(p2p, "Probe Req with 11b rates only supported - ignore it");
 		return P2P_PREQ_NOT_P2P;
 	}
 
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
 		/* Could not parse P2P attributes */
+		p2p_dbg(p2p, "Could not parse P2P attributes in Probe Req - ignore it");
 		return P2P_PREQ_NOT_P2P;
 	}
 
 	if (msg.device_id &&
 	    os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
 		/* Device ID did not match */
+		p2p_dbg(p2p, "Probe Req requested Device ID " MACSTR " did not match - ignore it",
+			MAC2STR(msg.device_id));
 		p2p_parse_free(&msg);
 		return P2P_PREQ_NOT_PROCESSED;
 	}
@@ -2066,6 +2039,7 @@
 	if (msg.wps_attributes &&
 	    !p2p_match_dev_type(p2p, msg.wps_attributes)) {
 		/* No match with Requested Device Type */
+		p2p_dbg(p2p, "Probe Req requestred Device Type did not match - ignore it");
 		p2p_parse_free(&msg);
 		return P2P_PREQ_NOT_PROCESSED;
 	}
@@ -2073,6 +2047,7 @@
 
 	if (!p2p->cfg->send_probe_resp) {
 		/* Response generated elsewhere */
+		p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
@@ -2163,10 +2138,12 @@
 
 	if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
 	    p2p->invite_peer &&
+	    (p2p->invite_peer->flags & P2P_DEV_WAIT_INV_REQ_ACK) &&
 	    os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
 	    == 0) {
 		/* Received a Probe Request from Invite peer */
 		p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
+		eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
 		eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
 		return P2P_PREQ_PROCESSED;
 	}
@@ -2408,16 +2385,7 @@
 			p2p->cfg->num_pref_chan = 0;
 	}
 
-#ifdef ANDROID_P2P
-	/* 100ms listen time is too less to receive the response frames in some scenarios
-	 * increasing min listen time to 200ms.
-	 */
-	p2p->min_disc_int = 2;
-	/* SD_FAIR_POLICY: Initializing the SD current serviced pointer to NULL */
-	p2p->sd_dev_list = NULL;
-#else
 	p2p->min_disc_int = 1;
-#endif
 	p2p->max_disc_int = 3;
 	p2p->max_disc_tu = -1;
 
@@ -2437,6 +2405,11 @@
 
 	p2p->go_timeout = 100;
 	p2p->client_timeout = 20;
+	p2p->num_p2p_sd_queries = 0;
+
+	p2p_dbg(p2p, "initialized");
+	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
 
 	return p2p;
 }
@@ -2474,6 +2447,7 @@
 	wpabuf_free(p2p->sd_resp);
 	os_free(p2p->after_scan_tx);
 	p2p_remove_wps_vendor_extensions(p2p);
+	os_free(p2p->no_go_freq.range);
 	os_free(p2p);
 }
 
@@ -2487,10 +2461,6 @@
 		dl_list_del(&dev->list);
 		p2p_device_free(p2p, dev);
 	}
-#ifdef ANDROID_P2P
-	/* SD_FAIR_POLICY: Initializing the SD current serviced pointer to NULL */
-	p2p->sd_dev_list = NULL;
-#endif
 	p2p_free_sd_queries(p2p);
 	os_free(p2p->after_scan_tx);
 	p2p->after_scan_tx = NULL;
@@ -2511,6 +2481,7 @@
 		p2p->go_neg_peer = NULL;
 
 	dev->wps_method = WPS_NOT_READY;
+	dev->oob_pw_id = 0;
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
 
@@ -2668,44 +2639,18 @@
 void p2p_continue_find(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
-#ifdef ANDROID_P2P
-	int skip=1;
-#endif
 	p2p_set_state(p2p, P2P_SEARCH);
 	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
-#ifdef ANDROID_P2P
-		/* SD_FAIR_POLICY: We need to give chance to all devices in the device list
-		 * There may be a scenario, where a particular peer device have
-		 * not registered any query response. When we send a SD request to such device,
-		 * no response will be received. And if we continue to get probe responses from that device, 
-		 * and if that device happens to be on top in our device list, 
-		 * we will always continue to send SD requests always to that peer only. 
-		 * We will not be able to send SD requests to other devices in that case. 
-		 * This implementation keeps track of last serviced peer device. 
-		 * And then takes the next one from the device list, in the next iteration.
-		 */
-		if (p2p->sd_dev_list && p2p->sd_dev_list != &p2p->devices) {
-			if(skip) {
-				if ((&dev->list == p2p->sd_dev_list) ) {
-					skip = 0;
-					if (dev->list.next == &p2p->devices)
-						p2p->sd_dev_list = NULL;
-				}
-				continue;
-			}
+		if (dev->sd_pending_bcast_queries == 0) {
+			/* Initialize with total number of registered broadcast
+			 * SD queries. */
+			dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
 		}
-		p2p->sd_dev_list = &dev->list;
-		wpa_printf(MSG_DEBUG, "P2P: ### Servicing %p dev->flags 0x%x SD schedule %s devaddr " MACSTR,
-			p2p->sd_dev_list, dev->flags, dev->flags & P2P_DEV_SD_SCHEDULE ? "TRUE": "FALSE",
-			MAC2STR(dev->info.p2p_device_addr));
-#endif
-		if (dev->flags & P2P_DEV_SD_SCHEDULE) {
-			if (p2p_start_sd(p2p, dev) == 0)
-				return;
-			else
-				break;
-		} else if (dev->req_config_methods &&
-			   !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+
+		if (p2p_start_sd(p2p, dev) == 0)
+			return;
+		if (dev->req_config_methods &&
+		    !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
 			p2p_dbg(p2p, "Send pending Provision Discovery Request to "
 				MACSTR " (config methods 0x%x)",
 				MAC2STR(dev->info.p2p_device_addr),
@@ -2726,10 +2671,7 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
 	if (!success) {
-		if (p2p->sd_peer) {
-			p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
-			p2p->sd_peer = NULL;
-		}
+		p2p->sd_peer = NULL;
 		p2p_continue_find(p2p);
 		return;
 	}
@@ -2774,7 +2716,8 @@
 			MAC2STR(dev->info.p2p_device_addr),
 			dev->req_config_methods);
 		p2p_send_prov_disc_req(p2p, dev,
-				       dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
+				       dev->flags & P2P_DEV_PD_FOR_JOIN,
+				       p2p->pd_force_freq);
 		return;
 	}
 }
@@ -2808,11 +2751,7 @@
 			p2p_continue_find(p2p);
 		else if (p2p->user_initiated_pd) {
 			p2p->pending_action_state = P2P_PENDING_PD;
-#ifdef ANDROID_P2P
-			p2p_set_timeout(p2p, 0, 350000);
-#else
 			p2p_set_timeout(p2p, 0, 300000);
-#endif
 		}
 		return;
 	}
@@ -2829,19 +2768,15 @@
 	/* Wait for response from the peer */
 	if (p2p->state == P2P_SEARCH)
 		p2p_set_state(p2p, P2P_PD_DURING_FIND);
-#ifdef ANDROID_P2P
-	p2p_set_timeout(p2p, 0, 350000);
-#else
 	p2p_set_timeout(p2p, 0, 200000);
-#endif
 }
 
 
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-			 struct os_time *rx_time, int level, const u8 *ies,
+			 struct os_reltime *rx_time, int level, const u8 *ies,
 			 size_t ies_len)
 {
-	if (os_time_before(rx_time, &p2p->find_start)) {
+	if (os_reltime_before(rx_time, &p2p->find_start)) {
 		/*
 		 * The driver may have cached (e.g., in cfg80211 BSS table) the
 		 * scan results for relatively long time. To avoid reporting
@@ -3210,7 +3145,12 @@
 		p2p_connect_send(p2p, p2p->go_neg_peer);
 		return;
 	}
-
+	if (p2p->go_neg_peer && p2p->go_neg_peer->oob_go_neg_freq > 0) {
+		p2p_dbg(p2p, "Skip connect-listen since GO Neg channel known (OOB)");
+		p2p_set_state(p2p, P2P_CONNECT_LISTEN);
+		p2p_set_timeout(p2p, 0, 30000);
+		return;
+	}
 	p2p_set_state(p2p, P2P_CONNECT_LISTEN);
 	p2p_listen_in_find(p2p, 0);
 }
@@ -3239,13 +3179,13 @@
 
 static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
 {
-	/*
-	 * TODO: could remain constantly in Listen state for some time if there
-	 * are no other concurrent uses for the radio. For now, go to listen
-	 * state once per second to give other uses a chance to use the radio.
-	 */
 	p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-	p2p_set_timeout(p2p, 0, 500000);
+
+	if (p2p->cfg->is_concurrent_session_active &&
+	    p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx))
+		p2p_set_timeout(p2p, 0, 500000);
+	else
+		p2p_set_timeout(p2p, 0, 200000);
 }
 
 
@@ -3276,7 +3216,6 @@
 	p2p_dbg(p2p, "Service Discovery Query timeout");
 	if (p2p->sd_peer) {
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-		p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
 		p2p->sd_peer = NULL;
 	}
 	p2p_continue_find(p2p);
@@ -3354,14 +3293,15 @@
 	if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) {
 		p2p_set_state(p2p, P2P_INVITE);
 		p2p_invite_send(p2p, p2p->invite_peer,
-				p2p->invite_go_dev_addr);
+				p2p->invite_go_dev_addr, p2p->invite_dev_pw_id);
 	} else {
 		if (p2p->invite_peer) {
 			p2p_dbg(p2p, "Invitation Request retry limit reached");
 			if (p2p->cfg->invitation_result)
 				p2p->cfg->invitation_result(
 					p2p->cfg->cb_ctx, -1, NULL, NULL,
-					p2p->invite_peer->info.p2p_device_addr);
+					p2p->invite_peer->info.p2p_device_addr,
+					0);
 		}
 		p2p_set_state(p2p, P2P_IDLE);
 	}
@@ -3436,10 +3376,6 @@
 	case P2P_INVITE_LISTEN:
 		p2p_timeout_invite_listen(p2p);
 		break;
-	case P2P_SEARCH_WHEN_READY:
-		break;
-	case P2P_CONTINUE_SEARCH_WHEN_READY:
-		break;
 	}
 }
 
@@ -3472,6 +3408,8 @@
 		return "Keypad";
 	case WPS_PBC:
 		return "PBC";
+	case WPS_NFC:
+		return "NFC";
 	}
 
 	return "??";
@@ -3522,7 +3460,7 @@
 	struct p2p_device *dev;
 	int res;
 	char *pos, *end;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (info == NULL)
 		return -1;
@@ -3533,7 +3471,7 @@
 	pos = buf;
 	end = buf + buflen;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	res = os_snprintf(pos, end - pos,
 			  "age=%d\n"
 			  "listen_freq=%d\n"
@@ -3548,7 +3486,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%s%s\n"
+			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
 			  "status=%d\n"
 			  "wait_count=%u\n"
 			  "invitation_reqs=%u\n",
@@ -3571,9 +3509,6 @@
 			  dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "",
 			  dev->flags & P2P_DEV_NOT_YET_READY ?
 			  "[NOT_YET_READY]" : "",
-			  dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "",
-			  dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" :
-			  "",
 			  dev->flags & P2P_DEV_PD_PEER_DISPLAY ?
 			  "[PD_PEER_DISPLAY]" : "",
 			  dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
@@ -3837,6 +3772,11 @@
 		return;
 	}
 
+	if (p2p->cfg->presence_resp) {
+		p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status,
+					msg.noa, msg.noa_len);
+	}
+
 	if (*msg.status) {
 		p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
 			*msg.status);
@@ -3934,8 +3874,10 @@
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ie, ie_len, &msg))
 		return;
-	if (msg.minor_reason_code == NULL)
+	if (msg.minor_reason_code == NULL) {
+		p2p_parse_free(&msg);
 		return;
+	}
 
 	p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
@@ -3956,8 +3898,10 @@
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ie, ie_len, &msg))
 		return;
-	if (msg.minor_reason_code == NULL)
+	if (msg.minor_reason_code == NULL) {
+		p2p_parse_free(&msg);
 		return;
+	}
 
 	p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
@@ -4045,6 +3989,31 @@
 }
 
 
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+		       const struct wpa_freq_range_list *list)
+{
+	struct wpa_freq_range *tmp;
+
+	if (list == NULL || list->num == 0) {
+		os_free(p2p->no_go_freq.range);
+		p2p->no_go_freq.range = NULL;
+		p2p->no_go_freq.num = 0;
+		return 0;
+	}
+
+	tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+	if (tmp == NULL)
+		return -1;
+	os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+	os_free(p2p->no_go_freq.range);
+	p2p->no_go_freq.range = tmp;
+	p2p->no_go_freq.num = list->num;
+	p2p_dbg(p2p, "Updated no GO chan list");
+
+	return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {
@@ -4107,10 +4076,16 @@
 }
 
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+			     const struct p2p_channels *chan,
+			     const struct p2p_channels *cli_chan)
 {
 	p2p_dbg(p2p, "Update channel list");
 	os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+	os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+		  sizeof(struct p2p_channels));
+	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
 }
 
 
@@ -4209,22 +4184,12 @@
 	return &dev->info;
 }
 
-#ifdef ANDROID_P2P
-int p2p_search_in_progress(struct p2p_data *p2p)
-{
-	if (p2p == NULL)
-		return 0;
-
-	return p2p->state == P2P_SEARCH;
-}
-#endif
 
 int p2p_in_progress(struct p2p_data *p2p)
 {
 	if (p2p == NULL)
 		return 0;
-	if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
-	    p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+	if (p2p->state == P2P_SEARCH)
 		return 2;
 	return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
 }
@@ -4240,13 +4205,6 @@
 }
 
 
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
-{
-	if (p2p && p2p->search_delay < delay)
-		p2p->search_delay = delay;
-}
-
-
 #ifdef CONFIG_WIFI_DISPLAY
 
 static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
@@ -4256,7 +4214,7 @@
 
 	for (g = 0; g < p2p->num_groups; g++) {
 		group = p2p->groups[g];
-		p2p_group_update_ies(group);
+		p2p_group_force_beacon_update_ies(group);
 	}
 }
 
@@ -4434,3 +4392,219 @@
 	va_end(ap);
 	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
+					      int client_freq,
+					      const u8 *go_dev_addr,
+					      const u8 *ssid, size_t ssid_len)
+{
+	struct wpabuf *buf;
+	u8 op_class, channel;
+	enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP;
+
+	buf = wpabuf_alloc(1000);
+	if (buf == NULL)
+		return NULL;
+
+	op_class = p2p->cfg->reg_class;
+	channel = p2p->cfg->channel;
+
+	p2p_buf_add_capability(buf, p2p->dev_capab &
+			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+	p2p_buf_add_device_info(buf, p2p, NULL);
+
+	if (p2p->num_groups > 0) {
+		role = P2P_GO_IN_A_GROUP;
+		p2p_freq_to_channel(p2p_group_get_freq(p2p->groups[0]),
+				    &op_class, &channel);
+	} else if (client_freq > 0) {
+		role = P2P_CLIENT_IN_A_GROUP;
+		p2p_freq_to_channel(client_freq, &op_class, &channel);
+	}
+
+	p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
+				       channel, role);
+
+	if (p2p->num_groups > 0) {
+		/* Limit number of clients to avoid very long message */
+		p2p_buf_add_group_info(p2p->groups[0], buf, 5);
+		p2p_group_buf_add_id(p2p->groups[0], buf);
+	} else if (client_freq > 0 &&
+		   go_dev_addr && !is_zero_ether_addr(go_dev_addr) &&
+		   ssid && ssid_len > 0) {
+		/*
+		 * Add the optional P2P Group ID to indicate in which group this
+		 * device is a P2P Client.
+		 */
+		p2p_buf_add_group_id(buf, go_dev_addr, ssid, ssid_len);
+	}
+
+	return buf;
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+					   int client_freq,
+					   const u8 *go_dev_addr,
+					   const u8 *ssid, size_t ssid_len)
+{
+	return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+				      ssid_len);
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+					   int client_freq,
+					   const u8 *go_dev_addr,
+					   const u8 *ssid, size_t ssid_len)
+{
+	return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+				      ssid_len);
+}
+
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+					struct p2p_nfc_params *params)
+{
+	struct p2p_message msg;
+	struct p2p_device *dev;
+	const u8 *p2p_dev_addr;
+	int freq;
+	enum p2p_role_indication role;
+
+	params->next_step = NO_ACTION;
+
+	if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len,
+				   params->p2p_attr, params->p2p_len, &msg)) {
+		p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC");
+		p2p_parse_free(&msg);
+		return -1;
+	}
+
+	if (msg.p2p_device_addr)
+		p2p_dev_addr = msg.p2p_device_addr;
+	else if (msg.device_id)
+		p2p_dev_addr = msg.device_id;
+	else {
+		p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
+		p2p_parse_free(&msg);
+		return -1;
+	}
+
+	if (msg.oob_dev_password) {
+		os_memcpy(params->oob_dev_pw, msg.oob_dev_password,
+			  msg.oob_dev_password_len);
+		params->oob_dev_pw_len = msg.oob_dev_password_len;
+	}
+
+	dev = p2p_create_device(p2p, p2p_dev_addr);
+	if (dev == NULL) {
+		p2p_parse_free(&msg);
+		return -1;
+	}
+
+	params->peer = &dev->info;
+
+	os_get_reltime(&dev->last_seen);
+	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+	p2p_copy_wps_info(p2p, dev, 0, &msg);
+
+	if (!msg.oob_go_neg_channel) {
+		p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
+		return -1;
+	}
+
+	if (msg.oob_go_neg_channel[3] == 0 &&
+	    msg.oob_go_neg_channel[4] == 0)
+		freq = 0;
+	else
+		freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3],
+					   msg.oob_go_neg_channel[4]);
+	if (freq < 0) {
+		p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+		return -1;
+	}
+	role = msg.oob_go_neg_channel[5];
+
+	if (role == P2P_GO_IN_A_GROUP) {
+		p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq);
+		params->go_freq = freq;
+	} else if (role == P2P_CLIENT_IN_A_GROUP) {
+		p2p_dbg(p2p, "Peer (client) OOB GO operating channel: %u MHz",
+			freq);
+		params->go_freq = freq;
+	} else
+		p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
+	dev->oob_go_neg_freq = freq;
+
+	if (!params->sel && role != P2P_GO_IN_A_GROUP) {
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+					   p2p->cfg->channel);
+		if (freq < 0) {
+			p2p_dbg(p2p, "Own listen channel not known");
+			return -1;
+		}
+		p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
+		dev->oob_go_neg_freq = freq;
+	}
+
+	if (msg.group_id) {
+		os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN);
+		params->go_ssid_len = msg.group_id_len - ETH_ALEN;
+		os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN,
+			  params->go_ssid_len);
+	}
+
+	p2p_parse_free(&msg);
+
+	if (dev->flags & P2P_DEV_USER_REJECTED) {
+		p2p_dbg(p2p, "Do not report rejected device");
+		return 0;
+	}
+
+	if (!(dev->flags & P2P_DEV_REPORTED)) {
+		p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info,
+				    !(dev->flags & P2P_DEV_REPORTED_ONCE));
+		dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+	}
+
+	if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0)
+		params->next_step = BOTH_GO;
+	else if (role == P2P_GO_IN_A_GROUP)
+		params->next_step = JOIN_GROUP;
+	else if (role == P2P_CLIENT_IN_A_GROUP) {
+		dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
+		params->next_step = PEER_CLIENT;
+	} else if (p2p->num_groups > 0)
+		params->next_step = AUTH_JOIN;
+	else if (params->sel)
+		params->next_step = INIT_GO_NEG;
+	else
+		params->next_step = RESP_GO_NEG;
+
+	return 0;
+}
+
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+				      int go_intent,
+				      const u8 *own_interface_addr)
+{
+
+	p2p->authorized_oob_dev_pw_id = dev_pw_id;
+	if (dev_pw_id == 0) {
+		p2p_dbg(p2p, "NFC OOB Password unauthorized for static handover");
+		return;
+	}
+
+	p2p_dbg(p2p, "NFC OOB Password (id=%u) authorized for static handover",
+		dev_pw_id);
+
+	p2p->go_intent = go_intent;
+	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7f845b2..08e7176 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -9,6 +9,8 @@
 #ifndef P2P_H
 #define P2P_H
 
+#include "wps/wps_defs.h"
+
 /**
  * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
  */
@@ -50,7 +52,7 @@
 };
 
 enum p2p_wps_method {
-	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC
 };
 
 /**
@@ -77,6 +79,8 @@
 
 	int ht40;
 
+	int vht;
+
 	/**
 	 * ssid - SSID of the group
 	 */
@@ -287,6 +291,20 @@
 	struct p2p_channels channels;
 
 	/**
+	 * cli_channels - Additional client channels
+	 *
+	 * This list of channels (if any) will be used when advertising local
+	 * channels during GO Negotiation or Invitation for the cases where the
+	 * local end may become the client. This may allow the peer to become a
+	 * GO on additional channels if it supports these options. The main use
+	 * case for this is to include passive-scan channels on devices that may
+	 * not know their current location and have configured most channels to
+	 * not allow initiation of radition (i.e., another device needs to take
+	 * master responsibilities).
+	 */
+	struct p2p_channels cli_channels;
+
+	/**
 	 * num_pref_chan - Number of pref_chan entries
 	 */
 	unsigned int num_pref_chan;
@@ -690,6 +708,8 @@
 	 *	persistent group (instead of invitation to join an active
 	 *	group)
 	 * @channels: Available operating channels for the group
+	 * @dev_pw_id: Device Password ID for NFC static handover or -1 if not
+	 *	used
 	 * Returns: Status code (P2P_SC_*)
 	 *
 	 * This optional callback can be used to implement persistent reconnect
@@ -711,7 +731,8 @@
 				 const u8 *go_dev_addr, const u8 *ssid,
 				 size_t ssid_len, int *go, u8 *group_bssid,
 				 int *force_freq, int persistent_group,
-				 const struct p2p_channels *channels);
+				 const struct p2p_channels *channels,
+				 int dev_pw_id);
 
 	/**
 	 * invitation_received - Callback on Invitation Request RX
@@ -742,6 +763,7 @@
 	 * @bssid: P2P Group BSSID or %NULL if not received
 	 * @channels: Available operating channels for the group
 	 * @addr: Peer address
+	 * @freq: Frequency (in MHz) indicated during invitation or 0
 	 *
 	 * This callback is used to indicate result of an Invitation procedure
 	 * started with a call to p2p_invite(). The indicated status code is
@@ -751,7 +773,7 @@
 	 */
 	void (*invitation_result)(void *ctx, int status, const u8 *bssid,
 				  const struct p2p_channels *channels,
-				  const u8 *addr);
+				  const u8 *addr, int freq);
 
 	/**
 	 * go_connected - Check whether we are connected to a GO
@@ -761,6 +783,26 @@
 	 * or 0 if not.
 	 */
 	int (*go_connected)(void *ctx, const u8 *dev_addr);
+
+	/**
+	 * presence_resp - Callback on Presence Response
+	 * @ctx: Callback context from cb_ctx
+	 * @src: Source address (GO's P2P Interface Address)
+	 * @status: Result of the request (P2P_SC_*)
+	 * @noa: Returned NoA value
+	 * @noa_len: Length of the NoA buffer in octets
+	 */
+	void (*presence_resp)(void *ctx, const u8 *src, u8 status,
+			      const u8 *noa, size_t noa_len);
+
+	/**
+	 * is_concurrent_session_active - Check whether concurrent session is
+	 * active on other virtual interfaces
+	 * @ctx: Callback context from cb_ctx
+	 * Returns: 1 if concurrent session is active on other virtual interface
+	 * or 0 if not.
+	 */
+	int (*is_concurrent_session_active)(void *ctx);
 };
 
 
@@ -935,7 +977,7 @@
 		int go_intent, const u8 *own_interface_addr,
 		unsigned int force_freq, int persistent_group,
 		const u8 *force_ssid, size_t force_ssid_len,
-		int pd_before_go_neg, unsigned int pref_freq);
+		int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id);
 
 /**
  * p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -963,7 +1005,7 @@
 		  int go_intent, const u8 *own_interface_addr,
 		  unsigned int force_freq, int persistent_group,
 		  const u8 *force_ssid, size_t force_ssid_len,
-		  unsigned int pref_freq);
+		  unsigned int pref_freq, u16 oob_pw_id);
 
 /**
  * p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -1065,12 +1107,14 @@
  * @persistent_group: Whether this is to reinvoke a persistent group
  * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
  *	force_freq == 0)
+ * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover
+ *	case or -1 if not used
  * Returns: 0 on success, -1 on failure
  */
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group, unsigned int pref_freq);
+	       int persistent_group, unsigned int pref_freq, int dev_pw_id);
 
 /**
  * p2p_presence_req - Request GO presence
@@ -1228,7 +1272,7 @@
  * start of a pending operation, e.g., to start a pending GO negotiation.
  */
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-			 struct os_time *rx_time, int level, const u8 *ies,
+			 struct os_reltime *rx_time, int level, const u8 *ies,
 			 size_t ies_len);
 
 /**
@@ -1335,6 +1379,11 @@
 	size_t ssid_len;
 
 	/**
+	 * freq - Operating channel of the group
+	 */
+	int freq;
+
+	/**
 	 * cb_ctx - Context to use with callback functions
 	 */
 	void *cb_ctx;
@@ -1649,6 +1698,22 @@
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 
 /**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
  * p2p_get_pref_freq - Get channel from preferred channel list
  * @p2p: P2P module context from p2p_init()
  * @channels: List of channels
@@ -1657,7 +1722,9 @@
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
 			       const struct p2p_channels *channels);
 
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+void p2p_update_channel_list(struct p2p_data *p2p,
+			     const struct p2p_channels *chan,
+			     const struct p2p_channels *cli_chan);
 
 /**
  * p2p_set_best_channels - Update best channel information
@@ -1765,35 +1832,21 @@
 		      const struct p2p_channel *pref_chan);
 
 /**
+ * p2p_set_no_go_freq - Set no GO channel ranges
+ * @p2p: P2P module context from p2p_init()
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+		       const struct wpa_freq_range_list *list);
+
+/**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
  * Returns: 0 if P2P module is idle or 1 if an operation is in progress
  */
 int p2p_in_progress(struct p2p_data *p2p);
 
-#ifdef ANDROID_P2P
-/**
- * p2p_search_in_progress - Check whether a P2P SEARCH is in progress
- * @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
- */
-int p2p_search_in_progress(struct p2p_data *p2p);
-
-/**
- * p2p_search_pending - Check whether there is a deferred P2P SEARCH
- * @p2p: P2P module context from p2p_init()
- * Returns: 0 if there is no deferred P2P search or 1 if there is one
- */
-int p2p_search_pending(struct p2p_data *p2p);
-#endif
-
-/**
- * p2p_other_scan_completed - Notify completion of non-P2P scan
- * @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation was started
- */
-int p2p_other_scan_completed(struct p2p_data *p2p);
-
 const char * p2p_wps_method_text(enum p2p_wps_method method);
 
 /**
@@ -1805,8 +1858,6 @@
 void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
 			    u8 client_timeout);
 
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
-
 int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
 int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
 int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
@@ -1853,4 +1904,41 @@
  */
 const char * p2p_get_state_txt(struct p2p_data *p2p);
 
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+					   int client_freq,
+					   const u8 *go_dev_addr,
+					   const u8 *ssid, size_t ssid_len);
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+					   int client_freq,
+					   const u8 *go_dev_addr,
+					   const u8 *ssid, size_t ssid_len);
+
+struct p2p_nfc_params {
+	int sel;
+	const u8 *wsc_attr;
+	size_t wsc_len;
+	const u8 *p2p_attr;
+	size_t p2p_len;
+
+	enum {
+		NO_ACTION, JOIN_GROUP, AUTH_JOIN, INIT_GO_NEG, RESP_GO_NEG,
+		BOTH_GO, PEER_CLIENT
+	} next_step;
+	struct p2p_peer_info *peer;
+	u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 +
+		      WPS_OOB_DEVICE_PASSWORD_LEN];
+	size_t oob_dev_pw_len;
+	int go_freq;
+	u8 go_dev_addr[ETH_ALEN];
+	u8 go_ssid[32];
+	size_t go_ssid_len;
+};
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+					struct p2p_nfc_params *params);
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+				      int go_intent,
+				      const u8 *own_interface_addr);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 5838d35..664fade 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -258,6 +258,7 @@
 	wpabuf_put_data(buf, ssid, ssid_len);
 	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
 		   MAC2STR(dev_addr));
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
 }
 
 
@@ -327,13 +328,32 @@
 }
 
 
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
-			       const char *val)
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+				    u8 oper_class, u8 channel,
+				    enum p2p_role_indication role)
+{
+	/* OOB Group Owner Negotiation Channel */
+	wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
+	wpabuf_put_le16(buf, 6);
+	wpabuf_put_data(buf, country, 3);
+	wpabuf_put_u8(buf, oper_class); /* Operating Class */
+	wpabuf_put_u8(buf, channel); /* Channel Number */
+	wpabuf_put_u8(buf, (u8) role); /* Role indication */
+	wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
+		   "Class %u Channel %u Role %d",
+		   oper_class, channel, role);
+}
+
+
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+			      const char *val)
 {
 	size_t len;
 
-	wpabuf_put_be16(buf, attr);
 	len = val ? os_strlen(val) : 0;
+	if (wpabuf_tailroom(buf) < 4 + len)
+		return -1;
+	wpabuf_put_be16(buf, attr);
 #ifndef CONFIG_WPS_STRICT
 	if (len == 0) {
 		/*
@@ -341,36 +361,46 @@
 		 * attributes. As a workaround, send a space character if the
 		 * device attribute string is empty.
 		 */
+		if (wpabuf_tailroom(buf) < 3)
+			return -1;
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, ' ');
-		return;
+		return 0;
 	}
 #endif /* CONFIG_WPS_STRICT */
 	wpabuf_put_be16(buf, len);
 	if (val)
 		wpabuf_put_data(buf, val, len);
+	return 0;
 }
 
 
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
-		      int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+		     int all_attr)
 {
 	u8 *len;
 	int i;
 
+	if (wpabuf_tailroom(buf) < 6)
+		return -1;
 	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
 	len = wpabuf_put(buf, 1);
 	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
 
-	wps_build_version(buf);
+	if (wps_build_version(buf) < 0)
+		return -1;
 
 	if (all_attr) {
+		if (wpabuf_tailroom(buf) < 5)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_WPS_STATE);
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
 	}
 
 	if (pw_id >= 0) {
+		if (wpabuf_tailroom(buf) < 6)
+			return -1;
 		/* Device Password ID */
 		wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
 		wpabuf_put_be16(buf, 2);
@@ -380,33 +410,47 @@
 	}
 
 	if (all_attr) {
+		if (wpabuf_tailroom(buf) < 5)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
 		wpabuf_put_be16(buf, 1);
 		wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
 
-		wps_build_uuid_e(buf, p2p->cfg->uuid);
-		p2p_add_wps_string(buf, ATTR_MANUFACTURER,
-				   p2p->cfg->manufacturer);
-		p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
-		p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
-				   p2p->cfg->model_number);
-		p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
-				   p2p->cfg->serial_number);
+		if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+				       p2p->cfg->manufacturer) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+				       p2p->cfg->model_name) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+				       p2p->cfg->model_number) < 0 ||
+		    p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+				       p2p->cfg->serial_number) < 0)
+			return -1;
 
+		if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
 		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
 		wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
 
-		p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+		if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+		    < 0)
+			return -1;
 
+		if (wpabuf_tailroom(buf) < 6)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
 		wpabuf_put_be16(buf, 2);
 		wpabuf_put_be16(buf, p2p->cfg->config_methods);
 	}
 
-	wps_build_wfa_ext(buf, 0, NULL, 0);
+	if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+		return -1;
 
 	if (all_attr && p2p->cfg->num_sec_dev_types) {
+		if (wpabuf_tailroom(buf) <
+		    4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+			return -1;
 		wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
 		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
 				p2p->cfg->num_sec_dev_types);
@@ -428,4 +472,6 @@
 	}
 
 	p2p_buf_update_ie_hdr(buf, len);
+
+	return 0;
 }
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index bd583be..2e40db1 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -103,6 +103,8 @@
 		return DEV_PW_USER_SPECIFIED;
 	case WPS_PBC:
 		return DEV_PW_PUSHBUTTON;
+	case WPS_NFC:
+		return DEV_PW_NFC_CONNECTION_HANDOVER;
 	default:
 		return DEV_PW_DEFAULT;
 	}
@@ -118,6 +120,8 @@
 		return "Keypad";
 	case WPS_PBC:
 		return "PBC";
+	case WPS_NFC:
+		return "NFC";
 	default:
 		return "??";
 	}
@@ -131,6 +135,7 @@
 	u8 *len;
 	u8 group_capab;
 	size_t extra = 0;
+	u16 pw_id;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -172,7 +177,14 @@
 	p2p_buf_update_ie_hdr(buf, len);
 
 	/* WPS IE with Device Password ID attribute */
-	p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+	pw_id = p2p_wps_method_pw_id(peer->wps_method);
+	if (peer->oob_pw_id)
+		pw_id = peer->oob_pw_id;
+	if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -205,6 +217,8 @@
 	}
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+	if (dev->oob_go_neg_freq > 0)
+		freq = dev->oob_go_neg_freq;
 	if (freq <= 0) {
 		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
 			MACSTR " to send GO Negotiation Request",
@@ -245,6 +259,7 @@
 	u8 *len;
 	u8 group_capab;
 	size_t extra = 0;
+	u16 pw_id;
 
 	p2p_dbg(p2p, "Building GO Negotiation Response");
 
@@ -307,9 +322,14 @@
 	p2p_buf_update_ie_hdr(buf, len);
 
 	/* WPS IE with Device Password ID attribute */
-	p2p_build_wps_ie(p2p, buf,
-			 p2p_wps_method_pw_id(peer ? peer->wps_method :
-					      WPS_NOT_READY), 0);
+	pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
+	if (peer && peer->oob_pw_id)
+		pw_id = peer->oob_pw_id;
+	if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+		p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+		wpabuf_free(buf);
+		return NULL;
+	}
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -339,6 +359,9 @@
 	int freq;
 	u8 op_reg_class, op_channel;
 	unsigned int i;
+	const int op_classes_5ghz[] = { 124, 115, 0 };
+	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+	const int op_classes_vht[] = { 128, 0 };
 
 	if (p2p->own_freq_preference > 0 &&
 	    p2p_freq_to_channel(p2p->own_freq_preference,
@@ -403,44 +426,28 @@
 		}
 	}
 
+	/* Try a channel where we might be able to use VHT */
+	if (p2p_channel_select(intersection, op_classes_vht,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible VHT channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
+	}
+
 	/* Try a channel where we might be able to use HT40 */
-	for (i = 0; i < intersection->reg_classes; i++) {
-		struct p2p_reg_class *c = &intersection->reg_class[i];
-		if (c->reg_class == 116 || c->reg_class == 117 ||
-		    c->reg_class == 126 || c->reg_class == 127) {
-			p2p_dbg(p2p, "Pick possible HT40 channel (reg_class %u channel %u) from intersection",
-				c->reg_class, c->channel[0]);
-			p2p->op_reg_class = c->reg_class;
-			p2p->op_channel = c->channel[0];
-			return;
-		}
+	if (p2p_channel_select(intersection, op_classes_ht40,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible HT40 channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
 	}
 
 	/* Prefer a 5 GHz channel */
-	for (i = 0; i < intersection->reg_classes; i++) {
-#ifdef ANDROID_P2P
-		struct p2p_reg_class prc;
-		struct p2p_reg_class *c = &prc;
-		p2p_copy_reg_class(c, &intersection->reg_class[i]);
-#else
-		struct p2p_reg_class *c = &intersection->reg_class[i];
-#endif
-		if ((c->reg_class == 115 || c->reg_class == 124) &&
-		    c->channels) {
-			unsigned int r;
-
-			/*
-			 * Pick one of the available channels in the operating
-			 * class at random.
-			 */
-			os_get_random((u8 *) &r, sizeof(r));
-			r %= c->channels;
-			p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
-				c->reg_class, c->channel[r]);
-			p2p->op_reg_class = c->reg_class;
-			p2p->op_channel = c->channel[r];
-			return;
-		}
+	if (p2p_channel_select(intersection, op_classes_5ghz,
+			       &p2p->op_reg_class, &p2p->op_channel) == 0) {
+		p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
 	}
 
 	/*
@@ -470,10 +477,17 @@
 static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
 				 u8 *status)
 {
-	struct p2p_channels intersection;
-	size_t i;
+	struct p2p_channels tmp, intersection;
 
-	p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+	p2p_channels_dump(p2p, "own channels", &p2p->channels);
+	p2p_channels_dump(p2p, "peer channels", &dev->channels);
+	p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+	p2p_channels_dump(p2p, "intersection", &tmp);
+	p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+	p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+	p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+	p2p_channels_dump(p2p, "intersection with local channel list",
+			  &intersection);
 	if (intersection.reg_classes == 0 ||
 	    intersection.reg_class[0].channels == 0) {
 		*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@@ -481,14 +495,6 @@
 		return -1;
 	}
 
-	for (i = 0; i < intersection.reg_classes; i++) {
-		struct p2p_reg_class *c;
-		c = &intersection.reg_class[i];
-		p2p_dbg(p2p, "reg_class %u", c->reg_class);
-		wpa_hexdump(MSG_DEBUG, "P2P: channels",
-			    c->channel, c->channels);
-	}
-
 	if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
 				   p2p->op_channel)) {
 		if (dev->flags & P2P_DEV_FORCE_FREQ) {
@@ -588,6 +594,25 @@
 	if (msg.status && *msg.status) {
 		p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
 			*msg.status);
+		if (dev && p2p->go_neg_peer == dev &&
+		    *msg.status == P2P_SC_FAIL_REJECTED_BY_USER) {
+			/*
+			 * This mechanism for using Status attribute in GO
+			 * Negotiation Request is not compliant with the P2P
+			 * specification, but some deployed devices use it to
+			 * indicate rejection of GO Negotiation in a case where
+			 * they have sent out GO Negotiation Response with
+			 * status 1. The P2P specification explicitly disallows
+			 * this. To avoid unnecessary interoperability issues
+			 * and extra frames, mark the pending negotiation as
+			 * failed and do not reply to this GO Negotiation
+			 * Request frame.
+			 */
+			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+			p2p_go_neg_failed(p2p, dev, *msg.status);
+			p2p_parse_free(&msg);
+			return;
+		}
 		goto fail;
 	}
 
@@ -595,10 +620,26 @@
 		dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
 	else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
 		p2p_add_dev_info(p2p, sa, dev, &msg);
+	else if (!dev->listen_freq && !dev->oper_freq) {
+		/*
+		 * This may happen if the peer entry was added based on PD
+		 * Request and no Probe Request/Response frame has been received
+		 * from this peer (or that information has timed out).
+		 */
+		p2p_dbg(p2p, "Update peer " MACSTR
+			" based on GO Neg Req since listen/oper freq not known",
+			MAC2STR(dev->info.p2p_device_addr));
+		p2p_add_dev_info(p2p, sa, dev, &msg);
+	}
+
 	if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
 		p2p_dbg(p2p, "User has rejected this peer");
 		status = P2P_SC_FAIL_REJECTED_BY_USER;
-	} else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
+	} else if (dev == NULL ||
+		   (dev->wps_method == WPS_NOT_READY &&
+		    (p2p->authorized_oob_dev_pw_id == 0 ||
+		     p2p->authorized_oob_dev_pw_id !=
+		     msg.dev_password_id))) {
 		p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
 			MAC2STR(sa));
 		status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
@@ -685,6 +726,28 @@
 			}
 			break;
 		default:
+			if (msg.dev_password_id &&
+			    msg.dev_password_id == dev->oob_pw_id) {
+				p2p_dbg(p2p, "Peer using NFC");
+				if (dev->wps_method != WPS_NFC) {
+					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;
+			}
+#ifdef CONFIG_WPS_NFC
+			if (p2p->authorized_oob_dev_pw_id &&
+			    msg.dev_password_id ==
+			    p2p->authorized_oob_dev_pw_id) {
+				p2p_dbg(p2p, "Using static handover with our device password from NFC Tag");
+				dev->wps_method = WPS_NFC;
+				dev->oob_pw_id = p2p->authorized_oob_dev_pw_id;
+				break;
+			}
+#endif /* CONFIG_WPS_NFC */
 			p2p_dbg(p2p, "Unsupported Device Password ID %d",
 				msg.dev_password_id);
 			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
@@ -1010,6 +1073,17 @@
 		}
 		break;
 	default:
+		if (msg.dev_password_id &&
+		    msg.dev_password_id == dev->oob_pw_id) {
+			p2p_dbg(p2p, "Peer using NFC");
+			if (dev->wps_method != WPS_NFC) {
+				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;
+		}
 		p2p_dbg(p2p, "Unsupported Device Password ID %d",
 			msg.dev_password_id);
 		status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
@@ -1042,9 +1116,10 @@
 	else
 		freq = dev->listen_freq;
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
-			    wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
+			    wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
 		p2p_go_neg_failed(p2p, dev, -1);
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	}
 	wpabuf_free(conf);
 	if (status != P2P_SC_SUCCESS) {
@@ -1080,9 +1155,11 @@
 
 	if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
 		p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
+		p2p_parse_free(&msg);
 		return;
 	}
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
 	if (msg.dialog_token != dev->dialog_token) {
 		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
@@ -1131,16 +1208,6 @@
 		}
 	}
 
-#ifdef ANDROID_P2P
-	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
-						     msg.operating_channel[4]);
-		p2p_dbg(p2p, "P2P: Peer operating channel preference: %d MHz",
-			dev->oper_freq);
-	} else
-		dev->oper_freq = 0;
-#endif
-
 	if (!msg.channel_list) {
 		p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 15e7622..395ca08 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -154,6 +154,7 @@
 		group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 	if (group->num_members >= group->cfg->max_clients)
 		group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
+	group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
 	p2p_buf_add_capability(ie, dev_capab, group_capab);
 }
 
@@ -397,10 +398,38 @@
 #endif /* CONFIG_WIFI_DISPLAY */
 
 
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+			    int max_clients)
+{
+	u8 *group_info;
+	int count = 0;
+	struct p2p_group_member *m;
+
+	p2p_dbg(group->p2p, "* P2P Group Info");
+	group_info = wpabuf_put(buf, 0);
+	wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO);
+	wpabuf_put_le16(buf, 0); /* Length to be filled */
+	for (m = group->members; m; m = m->next) {
+		p2p_client_info(buf, m);
+		count++;
+		if (max_clients >= 0 && count >= max_clients)
+			break;
+	}
+	WPA_PUT_LE16(group_info + 1,
+		     (u8 *) wpabuf_put(buf, 0) - group_info - 3);
+}
+
+
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf)
+{
+	p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid,
+			     group->cfg->ssid_len);
+}
+
+
 static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
 {
 	struct wpabuf *p2p_subelems, *ie;
-	struct p2p_group_member *m;
 
 	p2p_subelems = wpabuf_alloc(500);
 	if (p2p_subelems == NULL)
@@ -413,17 +442,8 @@
 	p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
 
 	/* P2P Group Info: Only when at least one P2P Client is connected */
-	if (group->members) {
-		u8 *group_info;
-		group_info = wpabuf_put(p2p_subelems, 0);
-		wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
-		wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
-		for (m = group->members; m; m = m->next)
-			p2p_client_info(p2p_subelems, m);
-		WPA_PUT_LE16(group_info + 1,
-			     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
-			     3);
-	}
+	if (group->members)
+		p2p_buf_add_group_info(group, p2p_subelems, -1);
 
 	ie = p2p_group_encaps_probe_resp(p2p_subelems);
 	wpabuf_free(p2p_subelems);
@@ -980,3 +1000,16 @@
 	return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
 			 group->cfg->ssid_len) == 0;
 }
+
+
+void p2p_group_force_beacon_update_ies(struct p2p_group *group)
+{
+	group->beacon_update = 1;
+	p2p_group_update_ies(group);
+}
+
+
+int p2p_group_get_freq(struct p2p_group *group)
+{
+	return group->cfg->freq;
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 81e521e..6de3461 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -12,6 +12,8 @@
 #include "utils/list.h"
 #include "p2p.h"
 
+enum p2p_role_indication;
+
 enum p2p_go_state {
 	UNKNOWN_GO,
 	LOCAL_GO,
@@ -23,9 +25,11 @@
  */
 struct p2p_device {
 	struct dl_list list;
-	struct os_time last_seen;
+	struct os_reltime last_seen;
 	int listen_freq;
+	int oob_go_neg_freq;
 	enum p2p_wps_method wps_method;
+	u16 oob_pw_id;
 
 	struct p2p_peer_info info;
 
@@ -77,8 +81,6 @@
 #define P2P_DEV_PROBE_REQ_ONLY BIT(0)
 #define P2P_DEV_REPORTED BIT(1)
 #define P2P_DEV_NOT_YET_READY BIT(2)
-#define P2P_DEV_SD_INFO BIT(3)
-#define P2P_DEV_SD_SCHEDULE BIT(4)
 #define P2P_DEV_PD_PEER_DISPLAY BIT(5)
 #define P2P_DEV_PD_PEER_KEYPAD BIT(6)
 #define P2P_DEV_USER_REJECTED BIT(7)
@@ -93,6 +95,7 @@
 #define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
 #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)
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -105,6 +108,7 @@
 
 	u8 go_timeout;
 	u8 client_timeout;
+	int sd_pending_bcast_queries;
 };
 
 struct p2p_sd_query {
@@ -205,16 +209,6 @@
 		 * P2P_INVITE_LISTEN - Listen during Invite
 		 */
 		P2P_INVITE_LISTEN,
-
-		/**
-		 * P2P_SEARCH_WHEN_READY - Waiting to start Search
-		 */
-		P2P_SEARCH_WHEN_READY,
-
-		/**
-		 * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
-		 */
-		P2P_CONTINUE_SEARCH_WHEN_READY,
 	} state;
 
 	/**
@@ -237,14 +231,6 @@
 	 */
 	struct dl_list devices;
 
-#ifdef ANDROID_P2P
-	/**
-	 * sd_dev_list - device pointer to be serviced next
-	 * for service discovery
-	 */
-	struct dl_list *sd_dev_list;
-#endif
-
 	/**
 	 * go_neg_peer - Pointer to GO Negotiation peer
 	 */
@@ -257,6 +243,7 @@
 
 	const u8 *invite_go_dev_addr;
 	u8 invite_go_dev_addr_buf[ETH_ALEN];
+	int invite_dev_pw_id;
 
 	/**
 	 * sd_peer - Pointer to Service Discovery peer
@@ -268,6 +255,12 @@
 	 */
 	struct p2p_sd_query *sd_query;
 
+	/**
+	 * num_p2p_sd_queries - Total number of broadcast SD queries present in
+	 * the list
+	 */
+	int num_p2p_sd_queries;
+
 	/* GO Negotiation data */
 
 	/**
@@ -324,6 +317,8 @@
 	 */
 	struct p2p_channels channels;
 
+	struct wpa_freq_range_list no_go_freq;
+
 	enum p2p_pending_action_state {
 		P2P_NO_PENDING_ACTION,
 		P2P_PENDING_GO_NEG_REQUEST,
@@ -401,7 +396,7 @@
 	u8 *find_dev_id;
 	u8 find_dev_id_buf[ETH_ALEN];
 
-	struct os_time find_start; /* time of last p2p_find start */
+	struct os_reltime find_start; /* time of last p2p_find start */
 
 	struct p2p_group **groups;
 	size_t num_groups;
@@ -450,6 +445,14 @@
 	 */
 	int pd_retries;
 
+	/**
+	 * pd_force_freq - Forced frequency for PD retries or 0 to auto-select
+	 *
+	 * This is is used during PD retries for join-a-group case to use the
+	 * correct operating frequency determined from a BSS entry for the GO.
+	 */
+	int pd_force_freq;
+
 	u8 go_timeout;
 	u8 client_timeout;
 
@@ -470,6 +473,8 @@
 	struct wpabuf *wfd_assoc_bssid;
 	struct wpabuf *wfd_coupled_sink_info;
 #endif /* CONFIG_WIFI_DISPLAY */
+
+	u16 authorized_oob_dev_pw_id;
 };
 
 /**
@@ -511,6 +516,8 @@
 
 	const u8 *minor_reason_code;
 
+	const u8 *oob_go_neg_channel;
+
 	/* P2P Device Info */
 	const u8 *p2p_device_info;
 	size_t p2p_device_info_len;
@@ -522,6 +529,7 @@
 
 	/* WPS IE */
 	u16 dev_password_id;
+	int dev_password_id_present;
 	u16 wps_config_methods;
 	const u8 *wps_pri_dev_type;
 	const u8 *wps_sec_dev_type_list;
@@ -536,6 +544,8 @@
 	size_t model_number_len;
 	const u8 *serial_number;
 	size_t serial_number_len;
+	const u8 *oob_dev_password;
+	size_t oob_dev_password_len;
 
 	/* DS Parameter Set IE */
 	const u8 *ds_params;
@@ -570,16 +580,24 @@
 void p2p_channels_intersect(const struct p2p_channels *a,
 			    const struct p2p_channels *b,
 			    struct p2p_channels *res);
+void p2p_channels_union(const struct p2p_channels *a,
+			const struct p2p_channels *b,
+			struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+			       const struct wpa_freq_range_list *list);
 int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
 			  u8 channel);
-#ifdef ANDROID_P2P
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc);
-#endif
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+		       const struct p2p_channels *chan);
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+		       u8 *op_class, u8 *op_channel);
 
 /* p2p_parse.c */
 int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
 int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
 int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+			   size_t p2p_len, struct p2p_message *msg);
 void p2p_parse_free(struct p2p_message *msg);
 int p2p_attr_text(struct wpabuf *data, char *buf, char *end);
 int p2p_group_info_parse(const u8 *gi, size_t gi_len,
@@ -602,7 +620,12 @@
 int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
 				size_t group_id_len);
 void p2p_group_update_ies(struct p2p_group *group);
+void p2p_group_force_beacon_update_ies(struct p2p_group *group);
 struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+			    int max_clients);
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf);
+int p2p_group_get_freq(struct p2p_group *group);
 
 
 void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -634,8 +657,11 @@
 void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
 				   u16 interval);
 void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
-		      int all_attr);
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+				    u8 oper_class, u8 channel,
+				    enum p2p_role_indication role);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+		     int all_attr);
 
 /* p2p_sd.c */
 struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -681,7 +707,7 @@
 void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
 				 const u8 *data, size_t len);
 int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
-		    const u8 *go_dev_addr);
+		    const u8 *go_dev_addr, int dev_pw_id);
 void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
 void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
 
@@ -709,7 +735,7 @@
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
 		      struct p2p_device *dev, struct p2p_message *msg);
 int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
-		   struct os_time *rx_time, int level, const u8 *ies,
+		   struct os_reltime *rx_time, int level, const u8 *ies,
 		   size_t ies_len, int scan_res);
 struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
 struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
@@ -727,7 +753,8 @@
 		    size_t len, unsigned int wait_time);
 void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
-			unsigned int force_freq, unsigned int pref_freq);
+			unsigned int force_freq, unsigned int pref_freq,
+			int go);
 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 6b3dafb..30d218c 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -16,7 +16,8 @@
 
 static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
 						struct p2p_device *peer,
-						const u8 *go_dev_addr)
+						const u8 *go_dev_addr,
+						int dev_pw_id)
 {
 	struct wpabuf *buf;
 	u8 *len;
@@ -85,6 +86,11 @@
 		wpabuf_put_buf(buf, wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
+	if (dev_pw_id >= 0) {
+		/* WSC IE in Invitation Request for NFC static handover */
+		p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
+	}
+
 	return buf;
 }
 
@@ -228,7 +234,8 @@
 		status = p2p->cfg->invitation_process(
 			p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
 			msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
-			&go, group_bssid, &op_freq, persistent, &intersection);
+			&go, group_bssid, &op_freq, persistent, &intersection,
+			msg.dev_password_id_present ? msg.dev_password_id : -1);
 	}
 
 	if (op_freq) {
@@ -407,7 +414,7 @@
 		return;
 	}
 
-	if (!msg.channel_list) {
+	if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
 		p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
 			MACSTR, MAC2STR(sa));
 #ifdef CONFIG_P2P_STRICT
@@ -416,6 +423,9 @@
 #endif /* CONFIG_P2P_STRICT */
 		/* Try to survive without peer channel list */
 		channels = &p2p->channels;
+	} else if (!msg.channel_list) {
+		/* Non-success cases are not required to include Channel List */
+		channels = &p2p->channels;
 	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
 					   msg.channel_list,
 					   msg.channel_list_len) < 0) {
@@ -428,9 +438,15 @@
 		channels = &intersection;
 	}
 
-	if (p2p->cfg->invitation_result)
+	if (p2p->cfg->invitation_result) {
+		int freq = p2p_channel_to_freq(p2p->op_reg_class,
+					       p2p->op_channel);
+		if (freq < 0)
+			freq = 0;
 		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
-					    msg.group_bssid, channels, sa);
+					    msg.group_bssid, channels, sa,
+					    freq);
+	}
 
 	p2p_parse_free(&msg);
 
@@ -441,12 +457,14 @@
 
 
 int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
-		    const u8 *go_dev_addr)
+		    const u8 *go_dev_addr, int dev_pw_id)
 {
 	struct wpabuf *req;
 	int freq;
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+	if (freq <= 0)
+		freq = dev->oob_go_neg_freq;
 	if (freq <= 0) {
 		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
 			MACSTR " to send Invitation Request",
@@ -454,7 +472,7 @@
 		return -1;
 	}
 
-	req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
+	req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id);
 	if (req == NULL)
 		return -1;
 	if (p2p->state != P2P_IDLE)
@@ -466,10 +484,12 @@
 	dev->invitation_reqs++;
 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
 			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
-			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
+			    wpabuf_head(req), wpabuf_len(req), 500) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
 		/* Use P2P find to recover and retry */
 		p2p_set_timeout(p2p, 0, 0);
+	} else {
+		dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
 	}
 
 	wpabuf_free(req);
@@ -487,12 +507,15 @@
 		return;
 	}
 
+	if (success)
+		p2p->invite_peer->flags &= ~P2P_DEV_WAIT_INV_REQ_ACK;
+
 	/*
 	 * Use P2P find, if needed, to find the other device from its listen
 	 * channel.
 	 */
 	p2p_set_state(p2p, P2P_INVITE);
-	p2p_set_timeout(p2p, 0, success ? 350000 : 100000);
+	p2p_set_timeout(p2p, 0, success ? 500000 : 100000);
 }
 
 
@@ -519,7 +542,7 @@
 int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
 	       unsigned int force_freq, const u8 *go_dev_addr,
-	       int persistent_group, unsigned int pref_freq)
+	       int persistent_group, unsigned int pref_freq, int dev_pw_id)
 {
 	struct p2p_device *dev;
 
@@ -537,15 +560,22 @@
 		p2p->invite_go_dev_addr = NULL;
 	wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
 			  ssid, ssid_len);
+	if (dev_pw_id >= 0) {
+		p2p_dbg(p2p, "Invitation to use Device Password ID %d",
+			dev_pw_id);
+	}
+	p2p->invite_dev_pw_id = dev_pw_id;
 
 	dev = p2p_get_device(p2p, peer);
-	if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) {
+	if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
+			    dev->oob_go_neg_freq <= 0)) {
 		p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
 			MAC2STR(peer));
 		return -1;
 	}
 
-	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+				role != P2P_INVITE_ROLE_CLIENT) < 0)
 		return -1;
 
 	if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
@@ -576,5 +606,5 @@
 	os_memcpy(p2p->inv_ssid, ssid, ssid_len);
 	p2p->inv_ssid_len = ssid_len;
 	p2p->inv_persistent = persistent_group;
-	return p2p_invite_send(p2p, dev, go_dev_addr);
+	return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
 }
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index 097a31d..d6144a0 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -268,6 +268,19 @@
 		wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
 			   *msg->minor_reason_code);
 		break;
+	case P2P_ATTR_OOB_GO_NEG_CHANNEL:
+		if (len < 6) {
+			wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg "
+				   "Channel attribute (length %d)", len);
+			return -1;
+		}
+		msg->oob_go_neg_channel = data;
+		wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: "
+			   "Country %c%c(0x%02x) Operating Class %d "
+			   "Channel Number %d Role %d",
+			   data[0], data[1], data[2], data[3], data[4],
+			   data[5]);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
 			   "(length %d)", id, len);
@@ -340,6 +353,7 @@
 		msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
 		wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
 			   msg->dev_password_id);
+		msg->dev_password_id_present = 1;
 	}
 	if (attr.primary_dev_type) {
 		char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -367,6 +381,9 @@
 	msg->serial_number = attr.serial_number;
 	msg->serial_number_len = attr.serial_number_len;
 
+	msg->oob_dev_password = attr.oob_dev_password;
+	msg->oob_dev_password_len = attr.oob_dev_password_len;
+
 	return 0;
 }
 
@@ -450,6 +467,33 @@
 }
 
 
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+			   size_t p2p_len, struct p2p_message *msg)
+{
+	os_memset(msg, 0, sizeof(*msg));
+
+	msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
+	if (msg->wps_attributes &&
+	    p2p_parse_wps_ie(msg->wps_attributes, msg)) {
+		p2p_parse_free(msg);
+		return -1;
+	}
+
+	msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
+	if (msg->p2p_attributes &&
+	    p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
+		if (msg->p2p_attributes)
+			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
+					msg->p2p_attributes);
+		p2p_parse_free(msg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 /**
  * p2p_parse_free - Free temporary data from P2P parsing
  * @msg: Parsed attributes
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 54aa428..409405f 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -437,6 +437,7 @@
 	}
 
 	p2p->user_initiated_pd = user_initiated_pd;
+	p2p->pd_force_freq = force_freq;
 
 	if (p2p->user_initiated_pd)
 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
@@ -472,4 +473,5 @@
 	p2p->user_initiated_pd = 0;
 	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
 	p2p->pd_retries = 0;
+	p2p->pd_force_freq = 0;
 }
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 795ca6b..26b9c2d 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -52,6 +52,7 @@
 {
 	struct p2p_sd_query *q;
 	int wsd = 0;
+	int count = 0;
 
 	if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
 		return NULL; /* peer does not support SD */
@@ -64,8 +65,19 @@
 		/* Use WSD only if the peer indicates support or it */
 		if (q->wsd && !wsd)
 			continue;
-		if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
-			return q;
+		/* if the query is a broadcast query */
+		if (q->for_all_peers) {
+			/*
+			 * check if there are any broadcast queries pending for
+			 * this device
+			 */
+			if (dev->sd_pending_bcast_queries <= 0)
+				return NULL;
+			/* query number that needs to be send to the device */
+			if (count == dev->sd_pending_bcast_queries - 1)
+				return q;
+			count++;
+		}
 		if (!q->for_all_peers &&
 		    os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
 		    0)
@@ -76,14 +88,37 @@
 }
 
 
+static void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
+{
+	struct p2p_device *dev;
+
+	p2p->num_p2p_sd_queries--;
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (query_number <= dev->sd_pending_bcast_queries - 1) {
+			/*
+			 * Query not yet sent to the device and it is to be
+			 * removed, so update the pending count.
+			*/
+			dev->sd_pending_bcast_queries--;
+		}
+	}
+}
+
+
 static int p2p_unlink_sd_query(struct p2p_data *p2p,
 			       struct p2p_sd_query *query)
 {
 	struct p2p_sd_query *q, *prev;
+	int query_number = 0;
+
 	q = p2p->sd_queries;
 	prev = NULL;
 	while (q) {
 		if (q == query) {
+			/* If the query is a broadcast query, decrease one from
+			 * all the devices */
+			if (query->for_all_peers)
+				p2p_decrease_sd_bc_queries(p2p, query_number);
 			if (prev)
 				prev->next = q->next;
 			else
@@ -92,6 +127,8 @@
 				p2p->sd_query = NULL;
 			return 1;
 		}
+		if (q->for_all_peers)
+			query_number++;
 		prev = q;
 		q = q->next;
 	}
@@ -118,6 +155,7 @@
 		q = q->next;
 		p2p_free_sd_query(prev);
 	}
+	p2p->num_p2p_sd_queries = 0;
 }
 
 
@@ -262,6 +300,16 @@
 		ret = -1;
 	}
 
+	/* Update the pending broadcast SD query count for this device */
+	dev->sd_pending_bcast_queries--;
+
+	/*
+	 * If there are no pending broadcast queries for this device, mark it as
+	 * done (-1).
+	 */
+	if (dev->sd_pending_bcast_queries == 0)
+		dev->sd_pending_bcast_queries = -1;
+
 	wpabuf_free(req);
 
 	return ret;
@@ -430,15 +478,7 @@
 	u16 slen;
 	u16 update_indic;
 
-#ifdef ANDROID_P2P
-	if (p2p->state != P2P_SD_DURING_FIND) {
-		p2p_dbg(p2p, "P2P: #### Not ignoring unexpected GAS Initial Response from "
-			MACSTR " state %d", MAC2STR(sa), p2p->state);
-	}
-	if (p2p->sd_peer == NULL ||
-#else
 	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
-#endif
 	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
 		p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
 			MACSTR, MAC2STR(sa));
@@ -549,8 +589,6 @@
 	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
 	pos += 2;
 
-	p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
-	p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
 	p2p->sd_peer = NULL;
 
 	if (p2p->sd_query) {
@@ -653,15 +691,7 @@
 
 	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
 
-#ifdef ANDROID_P2P
-	if (p2p->state != P2P_SD_DURING_FIND) {
-		p2p_dbg(p2p, "P2P: #### Not ignoring unexpected GAS Comeback Response from "
-			MACSTR " state %d", MAC2STR(sa), p2p->state);
-	}
-	if (p2p->sd_peer == NULL ||
-#else
 	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
-#endif
 	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
 		p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
 			MACSTR, MAC2STR(sa));
@@ -803,8 +833,6 @@
 		return;
 	}
 
-	p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
-	p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
 	p2p->sd_peer = NULL;
 
 	if (p2p->sd_query) {
@@ -835,19 +863,6 @@
 		      const struct wpabuf *tlvs)
 {
 	struct p2p_sd_query *q;
-#ifdef ANDROID_P2P
-	/* Currently, supplicant doesn't support more than one pending broadcast SD request.
-	 * So reject if application is registering another one before cancelling the existing one.
-	 */
-	for (q = p2p->sd_queries; q; q = q->next) {
-		if( (q->for_all_peers == 1) && (!dst)) {
-				wpa_printf(MSG_ERROR, "P2P: Already one pending"
-					" Broadcast request. Please cancel the current one"
-					" before adding a new one");
-				return NULL;
-		}
-	}
-#endif
 
 	q = os_zalloc(sizeof(*q));
 	if (q == NULL)
@@ -870,8 +885,16 @@
 
 	if (dst == NULL) {
 		struct p2p_device *dev;
-		dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
-			dev->flags &= ~P2P_DEV_SD_INFO;
+
+		p2p->num_p2p_sd_queries++;
+
+		/* Update all the devices for the newly added broadcast query */
+		dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+			if (dev->sd_pending_bcast_queries <= 0)
+				dev->sd_pending_bcast_queries = 1;
+			else
+				dev->sd_pending_bcast_queries++;
+		}
 	}
 
 	return q;
@@ -901,9 +924,6 @@
 {
 	if (p2p_unlink_sd_query(p2p, req)) {
 		p2p_dbg(p2p, "Cancel pending SD query %p", req);
-#ifdef ANDROID_P2P
-		p2p->sd_dev_list = NULL;
-#endif
 		p2p_free_sd_query(req);
 		return 0;
 	}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a4c48f6..161a402 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -94,6 +94,10 @@
 		if (channel < 149 || channel > 161)
 			return -1;
 		return 5000 + 5 * channel;
+	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+		if (channel < 36 || channel > 161)
+			return -1;
+		return 5000 + 5 * channel;
 	}
 	return -1;
 }
@@ -204,6 +208,105 @@
 }
 
 
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+			       const struct p2p_reg_class *b_cl)
+{
+	size_t i, j;
+
+	for (i = 0; i < b_cl->channels; i++) {
+		for (j = 0; j < cl->channels; j++) {
+			if (b_cl->channel[i] == cl->channel[j])
+				break;
+		}
+		if (j == cl->channels) {
+			if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+				return;
+			cl->channel[cl->channels++] = b_cl->channel[i];
+		}
+	}
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+			const struct p2p_channels *b,
+			struct p2p_channels *res)
+{
+	size_t i, j;
+
+	if (a != res)
+		os_memcpy(res, a, sizeof(*res));
+
+	for (i = 0; i < res->reg_classes; i++) {
+		struct p2p_reg_class *cl = &res->reg_class[i];
+		for (j = 0; j < b->reg_classes; j++) {
+			const struct p2p_reg_class *b_cl = &b->reg_class[j];
+			if (cl->reg_class != b_cl->reg_class)
+				continue;
+			p2p_op_class_union(cl, b_cl);
+		}
+	}
+
+	for (j = 0; j < b->reg_classes; j++) {
+		const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+		for (i = 0; i < res->reg_classes; i++) {
+			struct p2p_reg_class *cl = &res->reg_class[i];
+			if (cl->reg_class == b_cl->reg_class)
+				break;
+		}
+
+		if (i == res->reg_classes) {
+			if (res->reg_classes == P2P_MAX_REG_CLASSES)
+				return;
+			os_memcpy(&res->reg_class[res->reg_classes++],
+				  b_cl, sizeof(struct p2p_reg_class));
+		}
+	}
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+			       const struct wpa_freq_range_list *list)
+{
+	size_t o, c;
+
+	if (list == NULL)
+		return;
+
+	o = 0;
+	while (o < chan->reg_classes) {
+		struct p2p_reg_class *op = &chan->reg_class[o];
+
+		c = 0;
+		while (c < op->channels) {
+			int freq = p2p_channel_to_freq(op->reg_class,
+						       op->channel[c]);
+			if (freq > 0 && freq_range_list_includes(list, freq)) {
+				op->channels--;
+				os_memmove(&op->channel[c],
+					   &op->channel[c + 1],
+					   op->channels - c);
+			} else
+				c++;
+		}
+
+		if (op->channels == 0) {
+			chan->reg_classes--;
+			os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+				   (chan->reg_classes - o) *
+				   sizeof(struct p2p_reg_class));
+		} else
+			o++;
+	}
+}
+
+
 /**
  * p2p_channels_includes - Check whether a channel is included in the list
  * @channels: List of supported channels
@@ -244,39 +347,9 @@
 }
 
 
-#ifdef ANDROID_P2P
-static int p2p_block_op_freq(unsigned int freq)
-{
-	return (freq >= 5170 && freq < 5745);
-}
-
-
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc)
-{
-	unsigned int i;
-
-	dc->reg_class = sc->reg_class;
-	dc->channels = 0;
-	for (i=0; i < sc->channels; i++) {
-		if (!p2p_block_op_freq(p2p_channel_to_freq(sc->reg_class,
-							   sc->channel[i]))) {
-			dc->channel[dc->channels] = sc->channel[i];
-			dc->channels++;
-		}
-	}
-	return dc->channels;
-}
-#endif
-
-
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
 	u8 op_reg_class, op_channel;
-
-#ifdef ANDROID_P2P
-	if (p2p_block_op_freq(freq))
-		return 0;
-#endif
 	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
 		return 0;
 	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
@@ -284,6 +357,29 @@
 }
 
 
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+	u8 op_reg_class, op_channel;
+	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+		return 0;
+	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+				     op_channel) &&
+		!freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+	u8 op_reg_class, op_channel;
+	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+		return 0;
+	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+				     op_channel) ||
+		p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+				      op_channel);
+}
+
+
 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
 			       const struct p2p_channels *channels)
 {
@@ -310,3 +406,66 @@
 
 	return 0;
 }
+
+
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+		       const struct p2p_channels *chan)
+{
+	char buf[500], *pos, *end;
+	size_t i, j;
+	int ret;
+
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	for (i = 0; i < chan->reg_classes; i++) {
+		const struct p2p_reg_class *c;
+		c = &chan->reg_class[i];
+		ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		for (j = 0; j < c->channels; j++) {
+			ret = os_snprintf(pos, end - pos, "%s%u",
+					  j == 0 ? "" : ",",
+					  c->channel[j]);
+			if (ret < 0 || ret >= end - pos)
+				break;
+			pos += ret;
+		}
+	}
+	*pos = '\0';
+
+	p2p_dbg(p2p, "%s:%s", title, buf);
+}
+
+
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+		       u8 *op_class, u8 *op_channel)
+{
+	unsigned int i, j, r;
+
+	for (j = 0; classes[j]; j++) {
+		for (i = 0; i < chans->reg_classes; i++) {
+			struct p2p_reg_class *c = &chans->reg_class[i];
+
+			if (c->channels == 0)
+				continue;
+
+			if (c->reg_class == classes[j]) {
+				/*
+				 * Pick one of the available channels in the
+				 * operating class at random.
+				 */
+				os_get_random((u8 *) &r, sizeof(r));
+				r %= c->channels;
+				*op_class = c->reg_class;
+				*op_channel = c->channel[r];
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
diff --git a/src/radius/Makefile b/src/radius/Makefile
index b199be8..b5d063d 100644
--- a/src/radius/Makefile
+++ b/src/radius/Makefile
@@ -1,7 +1,7 @@
 all: libradius.a
 
 clean:
-	rm -f *~ *.o *.d libradius.a
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libradius.a
 
 install:
 	@echo Nothing to be made.
diff --git a/src/radius/radius.c b/src/radius/radius.c
index d1feec9..1070fc7 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -233,7 +233,7 @@
 	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
 	{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
 };
-#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
 
 
 static struct radius_attr_type *radius_get_attr_type(u8 type)
@@ -249,25 +249,17 @@
 }
 
 
-static void print_char(char c)
-{
-	if (c >= 32 && c < 127)
-		printf("%c", c);
-	else
-		printf("<%02x>", c);
-}
-
-
 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
 {
 	struct radius_attr_type *attr;
-	int i, len;
+	int len;
 	unsigned char *pos;
+	char buf[1000];
 
 	attr = radius_get_attr_type(hdr->type);
 
-	printf("   Attribute %d (%s) length=%d\n",
-	       hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+	wpa_printf(MSG_INFO, "   Attribute %d (%s) length=%d",
+		   hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
 
 	if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
 		return;
@@ -277,47 +269,50 @@
 
 	switch (attr->data_type) {
 	case RADIUS_ATTR_TEXT:
-		printf("      Value: '");
-		for (i = 0; i < len; i++)
-			print_char(pos[i]);
-		printf("'\n");
+		printf_encode(buf, sizeof(buf), pos, len);
+		wpa_printf(MSG_INFO, "      Value: '%s'", buf);
 		break;
 
 	case RADIUS_ATTR_IP:
 		if (len == 4) {
 			struct in_addr addr;
 			os_memcpy(&addr, pos, 4);
-			printf("      Value: %s\n", inet_ntoa(addr));
-		} else
-			printf("      Invalid IP address length %d\n", len);
+			wpa_printf(MSG_INFO, "      Value: %s",
+				   inet_ntoa(addr));
+		} else {
+			wpa_printf(MSG_INFO, "      Invalid IP address length %d",
+				   len);
+		}
 		break;
 
 #ifdef CONFIG_IPV6
 	case RADIUS_ATTR_IPV6:
 		if (len == 16) {
-			char buf[128];
 			const char *atxt;
 			struct in6_addr *addr = (struct in6_addr *) pos;
 			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
-			printf("      Value: %s\n", atxt ? atxt : "?");
-		} else
-			printf("      Invalid IPv6 address length %d\n", len);
+			wpa_printf(MSG_INFO, "      Value: %s",
+				   atxt ? atxt : "?");
+		} else {
+			wpa_printf(MSG_INFO, "      Invalid IPv6 address length %d",
+				   len);
+		}
 		break;
 #endif /* CONFIG_IPV6 */
 
 	case RADIUS_ATTR_HEXDUMP:
 	case RADIUS_ATTR_UNDIST:
-		printf("      Value:");
-		for (i = 0; i < len; i++)
-			printf(" %02x", pos[i]);
-		printf("\n");
+		wpa_snprintf_hex(buf, sizeof(buf), pos, len);
+		wpa_printf(MSG_INFO, "      Value: %s", buf);
 		break;
 
 	case RADIUS_ATTR_INT32:
 		if (len == 4)
-			printf("      Value: %u\n", WPA_GET_BE32(pos));
+			wpa_printf(MSG_INFO, "      Value: %u",
+				   WPA_GET_BE32(pos));
 		else
-			printf("      Invalid INT32 length %d\n", len);
+			wpa_printf(MSG_INFO, "      Invalid INT32 length %d",
+				   len);
 		break;
 
 	default:
@@ -330,9 +325,9 @@
 {
 	size_t i;
 
-	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
-	       msg->hdr->code, radius_code_string(msg->hdr->code),
-	       msg->hdr->identifier, be_to_host16(msg->hdr->length));
+	wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
+		   msg->hdr->code, radius_code_string(msg->hdr->code),
+		   msg->hdr->identifier, be_to_host16(msg->hdr->length));
 
 	for (i = 0; i < msg->attr_used; i++) {
 		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -384,7 +379,7 @@
 	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
 				   auth, MD5_MAC_LEN);
 	if (attr == NULL) {
-		printf("WARNING: Could not add Message-Authenticator\n");
+		wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
 		return -1;
 	}
 	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
@@ -473,6 +468,27 @@
 }
 
 
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+				 size_t secret_len, const u8 *req_authenticator)
+{
+	const u8 *addr[2];
+	size_t len[2];
+
+	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+	os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
+	addr[0] = wpabuf_head(msg->buf);
+	len[0] = wpabuf_len(msg->buf);
+	addr[1] = secret;
+	len[1] = secret_len;
+	md5_vector(2, addr, len, msg->hdr->authenticator);
+
+	if (wpabuf_len(msg->buf) > 0xffff) {
+		wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+			   (unsigned long) wpabuf_len(msg->buf));
+	}
+}
+
+
 int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
 			       size_t secret_len)
 {
@@ -585,7 +601,7 @@
 	struct radius_attr_hdr *attr;
 
 	if (data_len > RADIUS_MAX_ATTR_LEN) {
-		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+		wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
 		       (unsigned long) data_len);
 		return NULL;
 	}
@@ -756,8 +772,7 @@
 		tmp = radius_get_attr_hdr(msg, i);
 		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
 			if (attr != NULL) {
-				printf("Multiple Message-Authenticator "
-				       "attributes in RADIUS message\n");
+				wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
 				return 1;
 			}
 			attr = tmp;
@@ -765,7 +780,7 @@
 	}
 
 	if (attr == NULL) {
-		printf("No Message-Authenticator attribute found\n");
+		wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
 		return 1;
 	}
 
@@ -786,7 +801,7 @@
 	}
 
 	if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
-		printf("Invalid Message-Authenticator!\n");
+		wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
 		return 1;
 	}
 
@@ -802,7 +817,7 @@
 	u8 hash[MD5_MAC_LEN];
 
 	if (sent_msg == NULL) {
-		printf("No matching Access-Request message found\n");
+		wpa_printf(MSG_INFO, "No matching Access-Request message found");
 		return 1;
 	}
 
@@ -823,7 +838,7 @@
 	len[3] = secret_len;
 	md5_vector(4, addr, len, hash);
 	if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
-		printf("Response Authenticator invalid!\n");
+		wpa_printf(MSG_INFO, "Response Authenticator invalid!");
 		return 1;
 	}
 
@@ -962,7 +977,8 @@
 	pos = key + 2;
 	left = len - 2;
 	if (left % 16) {
-		printf("Invalid ms key len %lu\n", (unsigned long) left);
+		wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+			   (unsigned long) left);
 		return NULL;
 	}
 
@@ -996,7 +1012,7 @@
 	}
 
 	if (plain[0] == 0 || plain[0] > plen - 1) {
-		printf("Failed to decrypt MPPE key\n");
+		wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
 		os_free(plain);
 		return NULL;
 	}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2031054..ad65b04 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -204,6 +204,9 @@
 			       const struct radius_hdr *req_hdr);
 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
 			    size_t secret_len);
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+				 size_t secret_len,
+				 const u8 *req_authenticator);
 int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
 			       size_t secret_len);
 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 425ad93..7625996 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -122,7 +122,7 @@
 	/**
 	 * last_attempt - Time of the last transmission attempt
 	 */
-	struct os_time last_attempt;
+	struct os_reltime last_attempt;
 
 	/**
 	 * shared_secret - Shared secret with the target RADIUS server
@@ -300,7 +300,7 @@
 {
 #ifndef CONFIG_NATIVE_WINDOWS
 	int _errno = errno;
-	perror("send[RADIUS]");
+	wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
 	    _errno == EBADF) {
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -351,7 +351,7 @@
 		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
 		       radius_msg_get_hdr(entry->msg)->identifier);
 
-	os_get_time(&entry->last_attempt);
+	os_get_reltime(&entry->last_attempt);
 	buf = radius_msg_get_buf(entry->msg);
 	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
 		radius_client_handle_send_error(radius, s, entry->msg_type);
@@ -361,8 +361,7 @@
 	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
 		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
 	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
-		printf("Removing un-ACKed RADIUS message due to too many "
-		       "failed retransmit attempts\n");
+		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
 		return 1;
 	}
 
@@ -374,7 +373,7 @@
 {
 	struct radius_client_data *radius = eloop_ctx;
 	struct hostapd_radius_servers *conf = radius->conf;
-	struct os_time now;
+	struct os_reltime now;
 	os_time_t first;
 	struct radius_msg_list *entry, *prev, *tmp;
 	int auth_failover = 0, acct_failover = 0;
@@ -384,7 +383,7 @@
 	if (!entry)
 		return;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	first = 0;
 
 	prev = NULL;
@@ -482,7 +481,7 @@
 
 static void radius_client_update_timeout(struct radius_client_data *radius)
 {
-	struct os_time now;
+	struct os_reltime now;
 	os_time_t first;
 	struct radius_msg_list *entry;
 
@@ -498,7 +497,7 @@
 			first = entry->next_try;
 	}
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	if (first < now.sec)
 		first = now.sec;
 	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
@@ -526,7 +525,7 @@
 
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL) {
-		printf("Failed to add RADIUS packet into retransmit list\n");
+		wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
 		radius_msg_free(msg);
 		return;
 	}
@@ -537,7 +536,7 @@
 	entry->msg_type = msg_type;
 	entry->shared_secret = shared_secret;
 	entry->shared_secret_len = shared_secret_len;
-	os_get_time(&entry->last_attempt);
+	os_get_reltime(&entry->last_attempt);
 	entry->first_try = entry->last_attempt.sec;
 	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
 	entry->attempts = 1;
@@ -547,8 +546,7 @@
 	radius_client_update_timeout(radius);
 
 	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
-		printf("Removing the oldest un-ACKed RADIUS packet due to "
-		       "retransmit list limits.\n");
+		wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
 		prev = NULL;
 		while (entry->next) {
 			prev = entry;
@@ -694,7 +692,7 @@
 	struct radius_rx_handler *handlers;
 	size_t num_handlers, i;
 	struct radius_msg_list *req, *prev_req;
-	struct os_time now;
+	struct os_reltime now;
 	struct hostapd_radius_server *rconf;
 	int invalid_authenticator = 0;
 
@@ -710,21 +708,20 @@
 
 	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
 	if (len < 0) {
-		perror("recv[RADIUS]");
+		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
 		return;
 	}
 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
 		       "server", len);
 	if (len == sizeof(buf)) {
-		printf("Possibly too long UDP frame for our buffer - "
-		       "dropping it\n");
+		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
 		return;
 	}
 
 	msg = radius_msg_parse(buf, len);
 	if (msg == NULL) {
-		printf("Parsing incoming RADIUS frame failed\n");
+		wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
 		rconf->malformed_responses++;
 		return;
 	}
@@ -775,7 +772,7 @@
 		goto fail;
 	}
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
 		(now.usec - req->last_attempt.usec) / 10000;
 	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
@@ -1041,13 +1038,14 @@
 		}
 
 		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
-			perror("bind[radius]");
+			wpa_printf(MSG_INFO, "bind[radius]: %s",
+				   strerror(errno));
 			return -1;
 		}
 	}
 
 	if (connect(sel_sock, addr, addrlen) < 0) {
-		perror("connect[radius]");
+		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
 		return -1;
 	}
 
@@ -1123,8 +1121,8 @@
 	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
 		       sizeof(action));
 	if (r == -1)
-		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
-			   "%s", strerror(errno));
+		wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+			   strerror(errno));
 #endif
 	return r;
 }
@@ -1137,7 +1135,8 @@
 
 	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else {
 		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
 		ok++;
@@ -1146,7 +1145,8 @@
 #ifdef CONFIG_IPV6
 	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else
 		ok++;
 #endif /* CONFIG_IPV6 */
@@ -1162,8 +1162,7 @@
 	    eloop_register_read_sock(radius->auth_serv_sock,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
 		return -1;
 	}
 
@@ -1172,8 +1171,7 @@
 	    eloop_register_read_sock(radius->auth_serv_sock6,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1189,7 +1187,8 @@
 
 	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else {
 		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
 		ok++;
@@ -1198,7 +1197,8 @@
 #ifdef CONFIG_IPV6
 	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+			   strerror(errno));
 	else
 		ok++;
 #endif /* CONFIG_IPV6 */
@@ -1214,8 +1214,7 @@
 	    eloop_register_read_sock(radius->acct_serv_sock,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
 		return -1;
 	}
 
@@ -1224,8 +1223,7 @@
 	    eloop_register_read_sock(radius->acct_serv_sock6,
 				     radius_client_receive, radius,
 				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
+		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
 		return -1;
 	}
 #endif /* CONFIG_IPV6 */
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index bded965..9655f4c 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
- * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -16,9 +16,6 @@
 #include "radius_das.h"
 
 
-extern int wpa_debug_level;
-
-
 struct radius_das_data {
 	int sock;
 	u8 *shared_secret;
@@ -41,11 +38,16 @@
 	struct radius_msg *reply;
 	u8 allowed[] = {
 		RADIUS_ATTR_USER_NAME,
+		RADIUS_ATTR_NAS_IP_ADDRESS,
 		RADIUS_ATTR_CALLING_STATION_ID,
+		RADIUS_ATTR_NAS_IDENTIFIER,
 		RADIUS_ATTR_ACCT_SESSION_ID,
 		RADIUS_ATTR_EVENT_TIMESTAMP,
 		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
 		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+#ifdef CONFIG_IPV6
+		RADIUS_ATTR_NAS_IPV6_ADDRESS,
+#endif /* CONFIG_IPV6 */
 		0
 	};
 	int error = 405;
@@ -70,6 +72,36 @@
 
 	os_memset(&attrs, 0, sizeof(attrs));
 
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				    &buf, &len, NULL) == 0) {
+		if (len != 4) {
+			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
+				   abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.nas_ip_addr = buf;
+	}
+
+#ifdef CONFIG_IPV6
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+				    &buf, &len, NULL) == 0) {
+		if (len != 16) {
+			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
+				   abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.nas_ipv6_addr = buf;
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+				    &buf, &len, NULL) == 0) {
+		attrs.nas_identifier = buf;
+		attrs.nas_identifier_len = len;
+	}
+
 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
 				    &buf, &len, NULL) == 0) {
 		if (len >= sizeof(tmp))
@@ -200,7 +232,8 @@
 				  (u8 *) &val, 4);
 	if (res == 4) {
 		u32 timestamp = ntohl(val);
-		if (abs(now.sec - timestamp) > das->time_window) {
+		if ((unsigned int) abs(now.sec - timestamp) >
+		    das->time_window) {
 			wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
 				   "Event-Timestamp (%u; local time %u) in "
 				   "packet from %s:%d - drop",
@@ -284,7 +317,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -292,7 +325,7 @@
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index 738b18b..e3ed540 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -18,6 +18,13 @@
 };
 
 struct radius_das_attrs {
+	/* NAS identification attributes */
+	const u8 *nas_ip_addr;
+	const u8 *nas_identifier;
+	size_t nas_identifier_len;
+	const u8 *nas_ipv6_addr;
+
+	/* Session identification attributes */
 	const u8 *sta_addr;
 	const u8 *user_name;
 	size_t user_name_len;
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 0144c9f..2904b2f 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -49,6 +49,13 @@
 	u32 bad_authenticators;
 	u32 packets_dropped;
 	u32 unknown_types;
+
+	u32 acct_requests;
+	u32 invalid_acct_requests;
+	u32 acct_responses;
+	u32 malformed_acct_requests;
+	u32 acct_bad_authenticators;
+	u32 unknown_acct_types;
 };
 
 /**
@@ -99,6 +106,11 @@
 	int auth_sock;
 
 	/**
+	 * acct_sock - Socket for RADIUS accounting messages
+	 */
+	int acct_sock;
+
+	/**
 	 * clients - List of authorized RADIUS clients
 	 */
 	struct radius_client *clients;
@@ -244,7 +256,7 @@
 	/**
 	 * start_time - Timestamp of server start
 	 */
-	struct os_time start_time;
+	struct os_reltime start_time;
 
 	/**
 	 * counters - Statistics counters for server operations
@@ -298,8 +310,6 @@
 };
 
 
-extern int wpa_debug_level;
-
 #define RADIUS_DEBUG(args...) \
 wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
 #define RADIUS_ERROR(args...) \
@@ -679,7 +689,7 @@
 	buf = radius_msg_get_buf(msg);
 	if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
 		   (struct sockaddr *) from, sizeof(*from)) < 0) {
-		perror("sendto[RADIUS SRV]");
+		wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
 		ret = -1;
 	}
 
@@ -750,7 +760,8 @@
 				     wpabuf_len(buf), 0,
 				     (struct sockaddr *) from, fromlen);
 			if (res < 0) {
-				perror("sendto[RADIUS SRV]");
+				wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+					   strerror(errno));
 			}
 			return 0;
 		}
@@ -842,7 +853,8 @@
 			     wpabuf_len(buf), 0,
 			     (struct sockaddr *) from, fromlen);
 		if (res < 0) {
-			perror("sendto[RADIUS SRV]");
+			wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+				   strerror(errno));
 		}
 		radius_msg_free(sess->last_reply);
 		sess->last_reply = reply;
@@ -897,7 +909,8 @@
 	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
 		       (struct sockaddr *) &from.ss, &fromlen);
 	if (len < 0) {
-		perror("recvfrom[radius_server]");
+		wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
@@ -978,6 +991,140 @@
 }
 
 
+static void radius_server_receive_acct(int sock, void *eloop_ctx,
+				       void *sock_ctx)
+{
+	struct radius_server_data *data = eloop_ctx;
+	u8 *buf = NULL;
+	union {
+		struct sockaddr_storage ss;
+		struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+		struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+	} from;
+	socklen_t fromlen;
+	int len, res;
+	struct radius_client *client = NULL;
+	struct radius_msg *msg = NULL, *resp = NULL;
+	char abuf[50];
+	int from_port = 0;
+	struct radius_hdr *hdr;
+	struct wpabuf *rbuf;
+
+	buf = os_malloc(RADIUS_MAX_MSG_LEN);
+	if (buf == NULL) {
+		goto fail;
+	}
+
+	fromlen = sizeof(from);
+	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
+		       (struct sockaddr *) &from.ss, &fromlen);
+	if (len < 0) {
+		wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+			   strerror(errno));
+		goto fail;
+	}
+
+#ifdef CONFIG_IPV6
+	if (data->ipv6) {
+		if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+			      sizeof(abuf)) == NULL)
+			abuf[0] = '\0';
+		from_port = ntohs(from.sin6.sin6_port);
+		RADIUS_DEBUG("Received %d bytes from %s:%d",
+			     len, abuf, from_port);
+
+		client = radius_server_get_client(data,
+						  (struct in_addr *)
+						  &from.sin6.sin6_addr, 1);
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (!data->ipv6) {
+		os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+		from_port = ntohs(from.sin.sin_port);
+		RADIUS_DEBUG("Received %d bytes from %s:%d",
+			     len, abuf, from_port);
+
+		client = radius_server_get_client(data, &from.sin.sin_addr, 0);
+	}
+
+	RADIUS_DUMP("Received data", buf, len);
+
+	if (client == NULL) {
+		RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+		data->counters.invalid_acct_requests++;
+		goto fail;
+	}
+
+	msg = radius_msg_parse(buf, len);
+	if (msg == NULL) {
+		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+		data->counters.malformed_acct_requests++;
+		client->counters.malformed_acct_requests++;
+		goto fail;
+	}
+
+	os_free(buf);
+	buf = NULL;
+
+	if (wpa_debug_level <= MSG_MSGDUMP) {
+		radius_msg_dump(msg);
+	}
+
+	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
+		RADIUS_DEBUG("Unexpected RADIUS code %d",
+			     radius_msg_get_hdr(msg)->code);
+		data->counters.unknown_acct_types++;
+		client->counters.unknown_acct_types++;
+		goto fail;
+	}
+
+	data->counters.acct_requests++;
+	client->counters.acct_requests++;
+
+	if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
+				       client->shared_secret_len)) {
+		RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
+		data->counters.acct_bad_authenticators++;
+		client->counters.acct_bad_authenticators++;
+		goto fail;
+	}
+
+	/* TODO: Write accounting information to a file or database */
+
+	hdr = radius_msg_get_hdr(msg);
+
+	resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
+	if (resp == NULL)
+		goto fail;
+
+	radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
+				    client->shared_secret_len,
+				    hdr->authenticator);
+
+	RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
+	if (wpa_debug_level <= MSG_MSGDUMP) {
+		radius_msg_dump(resp);
+	}
+	rbuf = radius_msg_get_buf(resp);
+	data->counters.acct_responses++;
+	client->counters.acct_responses++;
+	res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
+		     (struct sockaddr *) &from.ss, fromlen);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+			   strerror(errno));
+	}
+
+fail:
+	radius_msg_free(resp);
+	radius_msg_free(msg);
+	os_free(buf);
+}
+
+
 static int radius_server_disable_pmtu_discovery(int s)
 {
 	int r = -1;
@@ -1001,7 +1148,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -1011,7 +1158,7 @@
 	addr.sin_family = AF_INET;
 	addr.sin_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -1028,7 +1175,8 @@
 
 	s = socket(PF_INET6, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket[IPv6]");
+		wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -1037,7 +1185,7 @@
 	os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
 	addr.sin6_port = htons(port);
 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -1248,8 +1396,7 @@
 
 #ifndef CONFIG_IPV6
 	if (conf->ipv6) {
-		fprintf(stderr, "RADIUS server compiled without IPv6 "
-			"support.\n");
+		wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
 		return NULL;
 	}
 #endif /* CONFIG_IPV6 */
@@ -1258,7 +1405,7 @@
 	if (data == NULL)
 		return NULL;
 
-	os_get_time(&data->start_time);
+	os_get_reltime(&data->start_time);
 	data->conf_ctx = conf->conf_ctx;
 	data->eap_sim_db_priv = conf->eap_sim_db_priv;
 	data->ssl_ctx = conf->ssl_ctx;
@@ -1305,7 +1452,7 @@
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);
 	if (data->clients == NULL) {
-		printf("No RADIUS clients configured.\n");
+		wpa_printf(MSG_ERROR, "No RADIUS clients configured");
 		radius_server_deinit(data);
 		return NULL;
 	}
@@ -1317,8 +1464,7 @@
 #endif /* CONFIG_IPV6 */
 	data->auth_sock = radius_server_open_socket(conf->auth_port);
 	if (data->auth_sock < 0) {
-		printf("Failed to open UDP socket for RADIUS authentication "
-		       "server\n");
+		wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
 		radius_server_deinit(data);
 		return NULL;
 	}
@@ -1329,6 +1475,29 @@
 		return NULL;
 	}
 
+	if (conf->acct_port) {
+#ifdef CONFIG_IPV6
+		if (conf->ipv6)
+			data->acct_sock = radius_server_open_socket6(
+				conf->acct_port);
+		else
+#endif /* CONFIG_IPV6 */
+		data->acct_sock = radius_server_open_socket(conf->acct_port);
+		if (data->acct_sock < 0) {
+			wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
+			radius_server_deinit(data);
+			return NULL;
+		}
+		if (eloop_register_read_sock(data->acct_sock,
+					     radius_server_receive_acct,
+					     data, NULL)) {
+			radius_server_deinit(data);
+			return NULL;
+		}
+	} else {
+		data->acct_sock = -1;
+	}
+
 	return data;
 }
 
@@ -1347,6 +1516,11 @@
 		close(data->auth_sock);
 	}
 
+	if (data->acct_sock >= 0) {
+		eloop_unregister_read_sock(data->acct_sock);
+		close(data->acct_sock);
+	}
+
 	radius_server_free_clients(data, data->clients);
 
 	os_free(data->pac_opaque_encr_key);
@@ -1373,7 +1547,7 @@
 	int ret, uptime;
 	unsigned int idx;
 	char *end, *pos;
-	struct os_time now;
+	struct os_reltime now;
 	struct radius_client *cli;
 
 	/* RFC 2619 - RADIUS Authentication Server MIB */
@@ -1384,7 +1558,7 @@
 	pos = buf;
 	end = buf + buflen;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	uptime = (now.sec - data->start_time.sec) * 100 +
 		((now.usec - data->start_time.usec) / 10000) % 100;
 	ret = os_snprintf(pos, end - pos,
@@ -1410,7 +1584,13 @@
 			  "radiusAuthServTotalMalformedAccessRequests=%u\n"
 			  "radiusAuthServTotalBadAuthenticators=%u\n"
 			  "radiusAuthServTotalPacketsDropped=%u\n"
-			  "radiusAuthServTotalUnknownTypes=%u\n",
+			  "radiusAuthServTotalUnknownTypes=%u\n"
+			  "radiusAccServTotalRequests=%u\n"
+			  "radiusAccServTotalInvalidRequests=%u\n"
+			  "radiusAccServTotalResponses=%u\n"
+			  "radiusAccServTotalMalformedRequests=%u\n"
+			  "radiusAccServTotalBadAuthenticators=%u\n"
+			  "radiusAccServTotalUnknownTypes=%u\n",
 			  data->counters.access_requests,
 			  data->counters.invalid_requests,
 			  data->counters.dup_access_requests,
@@ -1420,7 +1600,13 @@
 			  data->counters.malformed_access_requests,
 			  data->counters.bad_authenticators,
 			  data->counters.packets_dropped,
-			  data->counters.unknown_types);
+			  data->counters.unknown_types,
+			  data->counters.acct_requests,
+			  data->counters.invalid_acct_requests,
+			  data->counters.acct_responses,
+			  data->counters.malformed_acct_requests,
+			  data->counters.acct_bad_authenticators,
+			  data->counters.unknown_acct_types);
 	if (ret < 0 || ret >= end - pos) {
 		*pos = '\0';
 		return pos - buf;
@@ -1455,7 +1641,13 @@
 				  "radiusAuthServMalformedAccessRequests=%u\n"
 				  "radiusAuthServBadAuthenticators=%u\n"
 				  "radiusAuthServPacketsDropped=%u\n"
-				  "radiusAuthServUnknownTypes=%u\n",
+				  "radiusAuthServUnknownTypes=%u\n"
+				  "radiusAccServTotalRequests=%u\n"
+				  "radiusAccServTotalInvalidRequests=%u\n"
+				  "radiusAccServTotalResponses=%u\n"
+				  "radiusAccServTotalMalformedRequests=%u\n"
+				  "radiusAccServTotalBadAuthenticators=%u\n"
+				  "radiusAccServTotalUnknownTypes=%u\n",
 				  idx,
 				  abuf, mbuf,
 				  cli->counters.access_requests,
@@ -1466,7 +1658,13 @@
 				  cli->counters.malformed_access_requests,
 				  cli->counters.bad_authenticators,
 				  cli->counters.packets_dropped,
-				  cli->counters.unknown_types);
+				  cli->counters.unknown_types,
+				  cli->counters.acct_requests,
+				  cli->counters.invalid_acct_requests,
+				  cli->counters.acct_responses,
+				  cli->counters.malformed_acct_requests,
+				  cli->counters.acct_bad_authenticators,
+				  cli->counters.unknown_acct_types);
 		if (ret < 0 || ret >= end - pos) {
 			*pos = '\0';
 			return pos - buf;
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 284bd59..78f5fc2 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -22,6 +22,11 @@
 	int auth_port;
 
 	/**
+	 * acct_port - UDP port to listen to as an accounting server
+	 */
+	int acct_port;
+
+	/**
 	 * client_file - RADIUS client configuration file
 	 *
 	 * This file contains the RADIUS clients and the shared secret to be
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index 9c41962..adfd3df 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 789ac25..cb86dfb 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -516,7 +516,6 @@
 	struct wpa_peerkey *peerkey;
 	struct wpa_eapol_ie_parse kde;
 	u32 lifetime;
-	struct os_time now;
 
 	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
 		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
@@ -568,10 +567,8 @@
 	lifetime = WPA_GET_BE32(kde.lifetime);
 	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
 	if (lifetime > 1000000000)
-		lifetime = 1000000000; /* avoid overflowing expiration time */
+		lifetime = 1000000000; /* avoid overflowing eloop time */
 	peerkey->lifetime = lifetime;
-	os_get_time(&now);
-	peerkey->expiration = now.sec + lifetime;
 	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
 			       sm, peerkey);
 
@@ -736,7 +733,6 @@
 					       struct wpa_eapol_ie_parse *kde)
 {
 	u32 lifetime;
-	struct os_time now;
 
 	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
 		return;
@@ -755,8 +751,6 @@
 		   lifetime, peerkey->lifetime);
 	peerkey->lifetime = lifetime;
 
-	os_get_time(&now);
-	peerkey->expiration = now.sec + lifetime;
 	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
 	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
 			       sm, peerkey);
@@ -1116,7 +1110,7 @@
 	while (peerkey) {
 		prev = peerkey;
 		peerkey = peerkey->next;
-		os_free(prev);
+		wpa_supplicant_peerkey_free(sm, prev);
 	}
 	sm->peerkey = NULL;
 }
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index b8845f7..f420691 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -24,7 +24,6 @@
 	int smk_complete;
 	u8 smkid[PMKID_LEN];
 	u32 lifetime;
-	os_time_t expiration;
 	int cipher; /* Selected cipher (WPA_CIPHER_*) */
 	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int replay_counter_set;
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 33fa1a2..0960815 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -53,9 +53,9 @@
 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 {
 	struct rsn_pmksa_cache *pmksa = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
 		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 		pmksa->pmksa = entry->next;
@@ -80,13 +80,13 @@
 {
 	int sec;
 	struct rsn_pmksa_cache_entry *entry;
-	struct os_time now;
+	struct os_reltime now;
 
 	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
 	eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
 	if (pmksa->pmksa == NULL)
 		return;
-	os_get_time(&now);
+	os_get_reltime(&now);
 	sec = pmksa->pmksa->expiration - now.sec;
 	if (sec < 0)
 		sec = 0;
@@ -125,7 +125,7 @@
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (pmk_len > PMK_LEN)
 		return NULL;
@@ -137,7 +137,7 @@
 	entry->pmk_len = pmk_len;
 	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
 		  wpa_key_mgmt_sha256(akmp));
-	os_get_time(&now);
+	os_get_reltime(&now);
 	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
 	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
 		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
@@ -466,9 +466,9 @@
 	int i, ret;
 	char *pos = buf;
 	struct rsn_pmksa_cache_entry *entry;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	ret = os_snprintf(pos, buf + len - pos,
 			  "Index / AA / PMKID / expiration (in seconds) / "
 			  "opportunistic\n");
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index c51620e..915f85e 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -70,13 +70,14 @@
 }
 
 
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
+				 enum eapol_supp_result result,
 				 void *ctx)
 {
 	struct wpa_sm *sm = ctx;
 	u8 pmk[PMK_LEN];
 
-	if (success) {
+	if (result == EAPOL_SUPP_RESULT_SUCCESS) {
 		int res, pmk_len;
 		pmk_len = PMK_LEN;
 		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
@@ -100,13 +101,14 @@
 			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 				"RSN: failed to get master session key from "
 				"pre-auth EAPOL state machines");
-			success = 0;
+			result = EAPOL_SUPP_RESULT_FAILURE;
 		}
 	}
 
 	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
 		MACSTR " %s", MAC2STR(sm->preauth_bssid),
-		success ? "completed successfully" : "failed");
+		result == EAPOL_SUPP_RESULT_SUCCESS ? "completed successfully" :
+		"failed");
 
 	rsn_preauth_deinit(sm);
 	rsn_preauth_candidate_process(sm);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index e911ad0..8a978f7 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -136,6 +136,12 @@
 
 	u8 *ext_capab;
 	size_t ext_capab_len;
+
+	u8 *supp_channels;
+	size_t supp_channels_len;
+
+	u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
 };
 
 
@@ -633,6 +639,10 @@
 	peer->vht_capabilities = NULL;
 	os_free(peer->ext_capab);
 	peer->ext_capab = NULL;
+	os_free(peer->supp_channels);
+	peer->supp_channels = NULL;
+	os_free(peer->supp_oper_classes);
+	peer->supp_oper_classes = NULL;
 	peer->rsnie_i_len = peer->rsnie_p_len = 0;
 	peer->cipher = 0;
 	peer->tpk_set = peer->tpk_success = 0;
@@ -797,6 +807,28 @@
 }
 
 
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return "disabled";
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL)
+		return "peer does not exist";
+
+	if (!peer->tpk_success)
+		return "peer not connected";
+
+	return "connected";
+}
+
+
 static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
 				  const u8 *buf, size_t len)
 {
@@ -1434,6 +1466,58 @@
 }
 
 
+static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde,
+				   struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_channels) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported channels received");
+		return 0;
+	}
+
+	if (!peer->supp_channels ||
+	    peer->supp_channels_len < kde->supp_channels_len) {
+		os_free(peer->supp_channels);
+		peer->supp_channels = os_zalloc(kde->supp_channels_len);
+		if (peer->supp_channels == NULL)
+			return -1;
+	}
+
+	peer->supp_channels_len = kde->supp_channels_len;
+
+	os_memcpy(peer->supp_channels, kde->supp_channels,
+		  peer->supp_channels_len);
+	wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels",
+		    (u8 *) peer->supp_channels, peer->supp_channels_len);
+	return 0;
+}
+
+
+static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde,
+				       struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_oper_classes) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received");
+		return 0;
+	}
+
+	if (!peer->supp_oper_classes ||
+	    peer->supp_oper_classes_len < kde->supp_oper_classes_len) {
+		os_free(peer->supp_oper_classes);
+		peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len);
+		if (peer->supp_oper_classes == NULL)
+			return -1;
+	}
+
+	peer->supp_oper_classes_len = kde->supp_oper_classes_len;
+	os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes,
+		  peer->supp_oper_classes_len);
+	wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes",
+		    (u8 *) peer->supp_oper_classes,
+		    peer->supp_oper_classes_len);
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1546,6 +1630,12 @@
 	if (copy_peer_ext_capab(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_supp_channels(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+		goto error;
+
 	peer->qos_info = kde.qosinfo;
 
 	peer->aid = kde.aid;
@@ -1739,7 +1829,7 @@
 skip_rsn_check:
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
-				NULL, 0);
+				NULL, 0, NULL, 0, NULL, 0);
 	peer->tpk_in_progress = 1;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
@@ -1788,7 +1878,11 @@
 				    peer->ht_capabilities,
 				    peer->vht_capabilities,
 				    peer->qos_info, peer->ext_capab,
-				    peer->ext_capab_len) < 0)
+				    peer->ext_capab_len,
+				    peer->supp_channels,
+				    peer->supp_channels_len,
+				    peer->supp_oper_classes,
+				    peer->supp_oper_classes_len) < 0)
 		return -1;
 
 	if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
@@ -1817,7 +1911,7 @@
 	int ielen;
 	u16 status;
 	const u8 *pos;
-	int ret;
+	int ret = 0;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1916,6 +2010,12 @@
 	if (copy_peer_ext_capab(&kde, peer) < 0)
 		goto error;
 
+	if (copy_peer_supp_channels(&kde, peer) < 0)
+		goto error;
+
+	if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+		goto error;
+
 	peer->qos_info = kde.qosinfo;
 
 	peer->aid = kde.aid;
@@ -2034,11 +2134,19 @@
 		return -1;
 	}
 
-	ret = wpa_tdls_enable_link(sm, peer);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
-		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	if (!peer->tpk_success) {
+		/*
+		 * Enable Link only when tpk_success is 0, signifying that this
+		 * processing of TPK M2 frame is not because of a retransmission
+		 * during TDLS setup handshake.
+		 */
+		ret = wpa_tdls_enable_link(sm, peer);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+			wpa_tdls_do_teardown(
+				sm, peer,
+				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+		}
 	}
 	return ret;
 
@@ -2062,7 +2170,7 @@
 	u16 status;
 	const u8 *pos;
 	u32 lifetime;
-	int ret;
+	int ret = 0;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -2179,11 +2287,19 @@
 	}
 
 skip_rsn:
-	ret = wpa_tdls_enable_link(sm, peer);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
-		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	if (!peer->tpk_success) {
+		/*
+		 * Enable Link only when tpk_success is 0, signifying that this
+		 * processing of TPK M3 frame is not because of a retransmission
+		 * during TDLS setup handshake.
+		 */
+		ret = wpa_tdls_enable_link(sm, peer);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+			wpa_tdls_do_teardown(
+				sm, peer,
+				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+		}
 	}
 	return ret;
 error:
@@ -2251,7 +2367,7 @@
 
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
-				NULL, 0);
+				NULL, 0, NULL, 0, NULL, 0);
 
 	peer->tpk_in_progress = 1;
 
@@ -2284,7 +2400,7 @@
 		 * Disable previous link to allow renegotiation to be completed
 		 * on AP path.
 		 */
-		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+		wpa_tdls_disable_peer_link(sm, peer);
 	}
 }
 
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 292255c..4474c3b 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -379,6 +379,8 @@
 	struct wpa_ptk *ptk;
 	u8 buf[8];
 	int res;
+	u8 *kde, *kde_buf = NULL;
+	size_t kde_len;
 
 	if (wpa_sm_get_network_ctx(sm) == NULL) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
@@ -435,15 +437,39 @@
 	os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
 	sm->tptk_set = 1;
 
+	kde = sm->assoc_wpa_ie;
+	kde_len = sm->assoc_wpa_ie_len;
+
+#ifdef CONFIG_P2P
+	if (sm->p2p) {
+		kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
+		if (kde_buf) {
+			u8 *pos;
+			wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
+				   "into EAPOL-Key 2/4");
+			os_memcpy(kde_buf, kde, kde_len);
+			kde = kde_buf;
+			pos = kde + kde_len;
+			*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+			*pos++ = RSN_SELECTOR_LEN + 1;
+			RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+			pos += RSN_SELECTOR_LEN;
+			*pos++ = 0x01;
+			kde_len = pos - kde;
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
-				       sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
-				       ptk))
+				       kde, kde_len, ptk))
 		goto failed;
 
+	os_free(kde_buf);
 	os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
 	return;
 
 failed:
+	os_free(kde_buf);
 	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
 }
 
@@ -688,10 +714,11 @@
 	os_memcpy(gd.gtk, gtk, gtk_len);
 	gd.gtk_len = gtk_len;
 
-	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
-					      gtk_len, gtk_len,
-					      &gd.key_rsc_len, &gd.alg) ||
-	    wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
+	if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+	    (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					       gtk_len, gtk_len,
+					       &gd.key_rsc_len, &gd.alg) ||
+	     wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 			"RSN: Failed to install GTK");
 		return -1;
@@ -1089,6 +1116,14 @@
 		goto failed;
 	}
 
+#ifdef CONFIG_P2P
+	if (ie.ip_addr_alloc) {
+		os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4);
+		wpa_hexdump(MSG_DEBUG, "P2P: IP address info",
+			    sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr));
+	}
+#endif /* CONFIG_P2P */
+
 	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
 				       NULL, 0, &sm->ptk)) {
 		goto failed;
@@ -1112,7 +1147,10 @@
 	}
 	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
 
-	if (ie.gtk &&
+	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+		wpa_supplicant_key_neg_complete(sm, sm->bssid,
+						key_info & WPA_KEY_INFO_SECURE);
+	} else if (ie.gtk &&
 	    wpa_supplicant_pairwise_gtk(sm, key,
 					ie.gtk, ie.gtk_len, key_info) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1126,7 +1164,8 @@
 		goto failed;
 	}
 
-	wpa_sm_set_rekey_offload(sm);
+	if (ie.gtk)
+		wpa_sm_set_rekey_offload(sm);
 
 	return;
 
@@ -1347,13 +1386,14 @@
 			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
 		wpa_sm_cancel_auth_timeout(sm);
 		wpa_sm_set_state(sm, WPA_COMPLETED);
-
-		wpa_sm_set_rekey_offload(sm);
 	} else {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info &
 						WPA_KEY_INFO_SECURE);
 	}
+
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
@@ -2080,6 +2120,10 @@
 #ifdef CONFIG_TDLS
 	wpa_tdls_assoc(sm);
 #endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_P2P
+	os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
+#endif /* CONFIG_P2P */
 }
 
 
@@ -2092,6 +2136,7 @@
  */
 void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 {
+	peerkey_deinit(sm);
 	rsn_preauth_deinit(sm);
 	pmksa_cache_clear_current(sm);
 	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
@@ -2202,6 +2247,7 @@
 		} else
 			sm->ssid_len = 0;
 		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+		sm->p2p = config->p2p;
 	} else {
 		sm->network_ctx = NULL;
 		sm->peerkey_enabled = 0;
@@ -2211,6 +2257,7 @@
 		sm->eap_conf_ctx = NULL;
 		sm->ssid_len = 0;
 		sm->wpa_ptk_rekey = 0;
+		sm->p2p = 0;
 	}
 }
 
@@ -2703,3 +2750,37 @@
 	return 0;
 }
 #endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+			    const u8 *buf, size_t len)
+{
+	struct wpa_peerkey *peerkey;
+
+	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (!peerkey)
+		return 0;
+
+	wpa_sm_rx_eapol(sm, src_addr, buf, len);
+
+	return 1;
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_P2P
+
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
+{
+	if (sm == NULL || WPA_GET_BE32(sm->p2p_ip_addr) == 0)
+		return -1;
+	os_memcpy(buf, sm->p2p_ip_addr, 3 * 4);
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 26e9c6c..20b3f62 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -62,7 +62,10 @@
 				const struct ieee80211_ht_capabilities *ht_capab,
 				const struct ieee80211_vht_capabilities *vht_capab,
 				u8 qosinfo, const u8 *ext_capab,
-				size_t ext_capab_len);
+				size_t ext_capab_len, const u8 *supp_channels,
+				size_t supp_channels_len,
+				const u8 *supp_oper_classes,
+				size_t supp_oper_classes_len);
 #endif /* CONFIG_TDLS */
 	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
 				  const u8 *replay_ctr);
@@ -92,6 +95,7 @@
 	const u8 *ssid;
 	size_t ssid_len;
 	int wpa_ptk_rekey;
+	int p2p;
 };
 
 #ifndef CONFIG_NO_WPA
@@ -142,6 +146,8 @@
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
 
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -306,11 +312,19 @@
 
 #ifdef CONFIG_PEERKEY
 int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+			    const u8 *buf, size_t len);
 #else /* CONFIG_PEERKEY */
 static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
 {
 	return -1;
 }
+
+static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+					  const u8 *buf, size_t len)
+{
+	return 0;
+}
 #endif /* CONFIG_PEERKEY */
 
 #ifdef CONFIG_IEEE80211R
@@ -380,6 +394,7 @@
 void wpa_tdls_deinit(struct wpa_sm *sm);
 void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
 void wpa_tdls_disable_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_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 3a40c96..c8d8cfc 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -207,6 +207,8 @@
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
 	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
 	else {
 		wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
 			   sm->key_mgmt);
@@ -400,8 +402,7 @@
 		}
 	}
 
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
 		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
 			   "enabled for this connection");
 		return -1;
@@ -526,8 +527,7 @@
 	if (sm == NULL)
 		return 0;
 
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK)
+	if (!wpa_key_mgmt_ft(sm->key_mgmt))
 		return 0;
 
 	return sm->ft_completed;
@@ -678,8 +678,7 @@
 
 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
 
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
 		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
 			   "enabled for this connection");
 		return -1;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 0e0d373..75cfb47 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -58,6 +58,7 @@
 	u8 ssid[32];
 	size_t ssid_len;
 	int wpa_ptk_rekey;
+	int p2p;
 
 	u8 own_addr[ETH_ALEN];
 	const char *ifname;
@@ -122,6 +123,10 @@
 	u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
 	size_t assoc_resp_ies_len;
 #endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_P2P
+	u8 p2p_ip_addr[3 * 4];
+#endif /* CONFIG_P2P */
 };
 
 
@@ -286,14 +291,21 @@
 			size_t supp_rates_len,
 			const struct ieee80211_ht_capabilities *ht_capab,
 			const struct ieee80211_vht_capabilities *vht_capab,
-			u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
+			u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+			const u8 *supp_channels, size_t supp_channels_len,
+			const u8 *supp_oper_classes,
+			size_t supp_oper_classes_len)
 {
 	if (sm->ctx->tdls_peer_addset)
 		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
 						 aid, capability, supp_rates,
 						 supp_rates_len, ht_capab,
 						 vht_capab, qosinfo,
-						 ext_capab, ext_capab_len);
+						 ext_capab, ext_capab_len,
+						 supp_channels,
+						 supp_channels_len,
+						 supp_oper_classes,
+						 supp_oper_classes_len);
 	return -1;
 }
 #endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 50b9272..e58bdc4 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -345,6 +345,25 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+
+	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG,
+			    "WPA: IP Address Allocation in EAPOL-Key",
+			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+#endif /* CONFIG_P2P */
+
 	return 0;
 }
 
@@ -434,6 +453,12 @@
 			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) {
+			ie->supp_channels = pos + 2;
+			ie->supp_channels_len = pos[1];
+		} else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+			ie->supp_oper_classes = pos + 2;
+			ie->supp_oper_classes_len = pos[1];
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
 			ret = wpa_parse_generic(pos, end, ie);
 			if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 2c78801..82b6fa3 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -53,8 +53,16 @@
 	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;
+	size_t supp_oper_classes_len;
 	u8 qosinfo;
 	u16 aid;
+#ifdef CONFIG_P2P
+	const u8 *ip_addr_req;
+	const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index d212862..4578b22 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -57,8 +57,7 @@
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
 
 
 static const struct tls_cipher_data tls_ciphers[] = {
@@ -84,7 +83,7 @@
 	  CRYPTO_CIPHER_ALG_AES }
 };
 
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
 
 
 /**
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 940b4d8..8aad813 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -1,7 +1,7 @@
 all: libutils.a
 
 clean:
-	rm -f *~ *.o *.d libutils.a
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov libutils.a
 
 install:
 	@echo Nothing to be made.
@@ -11,6 +11,7 @@
 
 #CFLAGS += -DWPA_TRACE
 CFLAGS += -DCONFIG_IPV6
+CFLAGS += -DCONFIG_DEBUG_FILE
 
 LIB_OBJS= \
 	base64.o \
diff --git a/src/utils/common.c b/src/utils/common.c
index bf326cd..39751d4 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -400,7 +400,7 @@
 	int val;
 
 	while (*pos) {
-		if (len == maxlen)
+		if (len + 1 >= maxlen)
 			break;
 		switch (*pos) {
 		case '\\':
@@ -468,6 +468,8 @@
 			break;
 		}
 	}
+	if (maxlen > len)
+		buf[len] = '\0';
 
 	return len;
 }
@@ -576,6 +578,21 @@
 }
 
 
+int find_first_bit(u32 value)
+{
+	int pos = 0;
+
+	while (value) {
+		if (value & 0x1)
+			return pos;
+		value >>= 1;
+		pos++;
+	}
+
+	return -1;
+}
+
+
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len)
@@ -622,3 +639,191 @@
 
 	return res;
 }
+
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
+{
+	struct wpa_freq_range *freq = NULL, *n;
+	unsigned int count = 0;
+	const char *pos, *pos2, *pos3;
+
+	/*
+	 * Comma separated list of frequency ranges.
+	 * For example: 2412-2432,2462,5000-6000
+	 */
+	pos = value;
+	while (pos && pos[0]) {
+		n = os_realloc_array(freq, count + 1,
+				     sizeof(struct wpa_freq_range));
+		if (n == NULL) {
+			os_free(freq);
+			return -1;
+		}
+		freq = n;
+		freq[count].min = atoi(pos);
+		pos2 = os_strchr(pos, '-');
+		pos3 = os_strchr(pos, ',');
+		if (pos2 && (!pos3 || pos2 < pos3)) {
+			pos2++;
+			freq[count].max = atoi(pos2);
+		} else
+			freq[count].max = freq[count].min;
+		pos = pos3;
+		if (pos)
+			pos++;
+		count++;
+	}
+
+	os_free(res->range);
+	res->range = freq;
+	res->num = count;
+
+	return 0;
+}
+
+
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+			     unsigned int freq)
+{
+	unsigned int i;
+
+	if (list == NULL)
+		return 0;
+
+	for (i = 0; i < list->num; i++) {
+		if (freq >= list->range[i].min && freq <= list->range[i].max)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+char * freq_range_list_str(const struct wpa_freq_range_list *list)
+{
+	char *buf, *pos, *end;
+	size_t maxlen;
+	unsigned int i;
+	int res;
+
+	if (list->num == 0)
+		return NULL;
+
+	maxlen = list->num * 30;
+	buf = os_malloc(maxlen);
+	if (buf == NULL)
+		return NULL;
+	pos = buf;
+	end = buf + maxlen;
+
+	for (i = 0; i < list->num; i++) {
+		struct wpa_freq_range *range = &list->range[i];
+
+		if (range->min == range->max)
+			res = os_snprintf(pos, end - pos, "%s%u",
+					  i == 0 ? "" : ",", range->min);
+		else
+			res = os_snprintf(pos, end - pos, "%s%u-%u",
+					  i == 0 ? "" : ",",
+					  range->min, range->max);
+		if (res < 0 || res > end - pos) {
+			os_free(buf);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	return buf;
+}
+
+
+int int_array_len(const int *a)
+{
+	int i;
+	for (i = 0; a && a[i]; i++)
+		;
+	return i;
+}
+
+
+void int_array_concat(int **res, const int *a)
+{
+	int reslen, alen, i;
+	int *n;
+
+	reslen = int_array_len(*res);
+	alen = int_array_len(a);
+
+	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
+	if (n == NULL) {
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
+	for (i = 0; i <= alen; i++)
+		n[reslen + i] = a[i];
+	*res = n;
+}
+
+
+static int freq_cmp(const void *a, const void *b)
+{
+	int _a = *(int *) a;
+	int _b = *(int *) b;
+
+	if (_a == 0)
+		return 1;
+	if (_b == 0)
+		return -1;
+	return _a - _b;
+}
+
+
+void int_array_sort_unique(int *a)
+{
+	int alen;
+	int i, j;
+
+	if (a == NULL)
+		return;
+
+	alen = int_array_len(a);
+	qsort(a, alen, sizeof(int), freq_cmp);
+
+	i = 0;
+	j = 1;
+	while (a[i] && a[j]) {
+		if (a[i] == a[j]) {
+			j++;
+			continue;
+		}
+		a[++i] = a[j++];
+	}
+	if (a[i])
+		i++;
+	a[i] = 0;
+}
+
+
+void int_array_add_unique(int **res, int a)
+{
+	int reslen;
+	int *n;
+
+	for (reslen = 0; *res && (*res)[reslen]; reslen++) {
+		if ((*res)[reslen] == a)
+			return; /* already in the list */
+	}
+
+	n = os_realloc_array(*res, reslen + 2, sizeof(int));
+	if (n == NULL) {
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
+
+	n[reslen] = a;
+	n[reslen + 1] = 0;
+
+	*res = n;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 29f0b95..a85cc15 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -459,6 +459,14 @@
 #endif /* __GNUC__ */
 #endif /* __must_check */
 
+#ifndef __maybe_unused
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __maybe_unused __attribute__((unused))
+#else
+#define __maybe_unused
+#endif /* __GNUC__ */
+#endif /* __must_check */
+
 int hwaddr_aton(const char *txt, u8 *addr);
 int hwaddr_compact_aton(const char *txt, u8 *addr);
 int hwaddr_aton2(const char *txt, u8 *addr);
@@ -485,6 +493,7 @@
 
 char * wpa_config_parse_string(const char *value, size_t *len);
 int is_hex(const u8 *data, size_t len);
+int find_first_bit(u32 value);
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len);
@@ -505,6 +514,27 @@
 #include "wpa_debug.h"
 
 
+struct wpa_freq_range_list {
+	struct wpa_freq_range {
+		unsigned int min;
+		unsigned int max;
+	} *range;
+	unsigned int num;
+};
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+			     unsigned int freq);
+char * freq_range_list_str(const struct wpa_freq_range_list *list);
+
+int int_array_len(const int *a);
+void int_array_concat(int **res, const int *a);
+void int_array_sort_unique(int *a);
+void int_array_add_unique(int **res, int a);
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
  * networking socket uses that do not really result in a real problem and
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index f62e2b7..f83a232 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -31,7 +31,7 @@
 
 struct eloop_timeout {
 	struct dl_list list;
-	struct os_time time;
+	struct os_reltime time;
 	void *eloop_data;
 	void *user_data;
 	eloop_timeout_handler handler;
@@ -484,7 +484,7 @@
 	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	if (os_get_time(&timeout->time) < 0) {
+	if (os_get_reltime(&timeout->time) < 0) {
 		os_free(timeout);
 		return -1;
 	}
@@ -514,7 +514,7 @@
 
 	/* Maintain timeouts in order of increasing time */
 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
+		if (os_reltime_before(&timeout->time, &tmp->time)) {
 			dl_list_add(tmp->list.prev, &timeout->list);
 			return 0;
 		}
@@ -558,13 +558,13 @@
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
+			     struct os_reltime *remaining)
 {
 	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	remaining->sec = remaining->usec = 0;
 
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -573,8 +573,8 @@
 		    (timeout->eloop_data == eloop_data) &&
 		    (timeout->user_data == user_data)) {
 			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, remaining);
 			eloop_remove_timeout(timeout);
 			break;
 		}
@@ -599,6 +599,70 @@
 }
 
 
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&requested, &remaining)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&remaining, &requested)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
 #ifndef CONFIG_NATIVE_WINDOWS
 static void eloop_handle_alarm(int sig)
 {
@@ -714,7 +778,7 @@
 	struct timeval _tv;
 #endif /* CONFIG_ELOOP_POLL */
 	int res;
-	struct os_time tv, now;
+	struct os_reltime tv, now;
 
 #ifndef CONFIG_ELOOP_POLL
 	rfds = os_malloc(sizeof(*rfds));
@@ -731,9 +795,9 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
+			os_get_reltime(&now);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, &tv);
 			else
 				tv.sec = tv.usec = 0;
 #ifdef CONFIG_ELOOP_POLL
@@ -753,7 +817,8 @@
 			   timeout ? timeout_ms : -1);
 
 		if (res < 0 && errno != EINTR && errno != 0) {
-			perror("poll");
+			wpa_printf(MSG_INFO, "eloop: poll: %s",
+				   strerror(errno));
 			goto out;
 		}
 #else /* CONFIG_ELOOP_POLL */
@@ -763,7 +828,8 @@
 		res = select(eloop.max_sock + 1, rfds, wfds, efds,
 			     timeout ? &_tv : NULL);
 		if (res < 0 && errno != EINTR && errno != 0) {
-			perror("select");
+			wpa_printf(MSG_INFO, "eloop: select: %s",
+				   strerror(errno));
 			goto out;
 		}
 #endif /* CONFIG_ELOOP_POLL */
@@ -773,8 +839,8 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
+			os_get_reltime(&now);
+			if (!os_reltime_before(&now, &timeout->time)) {
 				void *eloop_data = timeout->eloop_data;
 				void *user_data = timeout->user_data;
 				eloop_timeout_handler handler =
@@ -819,9 +885,9 @@
 void eloop_destroy(void)
 {
 	struct eloop_timeout *timeout, *prev;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
 			      struct eloop_timeout, list) {
 		int sec, usec;
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 0037c63..07b8c0d 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -207,7 +207,7 @@
  */
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining);
+			     struct os_reltime *remaining);
 
 /**
  * eloop_is_timeout_registered - Check if a timeout is already registered
@@ -223,6 +223,40 @@
 				void *eloop_data, void *user_data);
 
 /**
+ * eloop_deplete_timeout - Deplete a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no
+ * timeout matched
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * deplete the timeout if remaining time is more than the requested time.
+ */
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data);
+
+/**
+ * eloop_replenish_timeout - Replenish a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no
+ * timeout matched
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * replenish the timeout if remaining time is less than the requested time.
+ */
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data);
+
+/**
  * eloop_register_signal - Register handler for signals
  * @sig: Signal number (e.g., SIGHUP)
  * @handler: Callback function to be called when the signal is received
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
deleted file mode 100644
index cb5e922..0000000
--- a/src/utils/eloop_none.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "list.h"
-#include "eloop.h"
-
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	eloop_sock_handler handler;
-};
-
-struct eloop_timeout {
-	struct dl_list list;
-	struct os_time time;
-	void *eloop_data;
-	void *user_data;
-	eloop_timeout_handler handler;
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	eloop_signal_handler handler;
-	int signaled;
-};
-
-struct eloop_data {
-	int max_sock, reader_count;
-	struct eloop_sock *readers;
-
-	struct dl_list timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-	int pending_terminate;
-
-	int terminate;
-	int reader_table_changed;
-};
-
-static struct eloop_data eloop;
-
-
-int eloop_init(void)
-{
-	os_memset(&eloop, 0, sizeof(eloop));
-	dl_list_init(&eloop.timeout);
-	return 0;
-}
-
-
-int eloop_register_read_sock(int sock, eloop_sock_handler handler,
-			     void *eloop_data, void *user_data)
-{
-	struct eloop_sock *tmp;
-
-	tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
-			       sizeof(struct eloop_sock));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	eloop.reader_count++;
-	eloop.readers = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-	eloop.reader_table_changed = 1;
-
-	return 0;
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
-	int i;
-
-	if (eloop.readers == NULL || eloop.reader_count == 0)
-		return;
-
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
-			break;
-	}
-	if (i == eloop.reader_count)
-		return;
-	if (i != eloop.reader_count - 1) {
-		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			   (eloop.reader_count - i - 1) *
-			   sizeof(struct eloop_sock));
-	}
-	eloop.reader_count--;
-	eloop.reader_table_changed = 1;
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   eloop_timeout_handler handler,
-			   void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp;
-	os_time_t now_sec;
-
-	timeout = os_zalloc(sizeof(*timeout));
-	if (timeout == NULL)
-		return -1;
-	if (os_get_time(&timeout->time) < 0) {
-		os_free(timeout);
-		return -1;
-	}
-	now_sec = timeout->time.sec;
-	timeout->time.sec += secs;
-	if (timeout->time.sec < now_sec) {
-		/*
-		 * Integer overflow - assume long enough timeout to be assumed
-		 * to be infinite, i.e., the timeout would never happen.
-		 */
-		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
-			   "ever happen - ignore it", secs);
-		os_free(timeout);
-		return 0;
-	}
-	timeout->time.usec += usecs;
-	while (timeout->time.usec >= 1000000) {
-		timeout->time.sec++;
-		timeout->time.usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-
-	/* Maintain timeouts in order of increasing time */
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
-			dl_list_add(tmp->list.prev, &timeout->list);
-			return 0;
-		}
-	}
-	dl_list_add_tail(&eloop.timeout, &timeout->list);
-
-	return 0;
-}
-
-
-static void eloop_remove_timeout(struct eloop_timeout *timeout)
-{
-	dl_list_del(&timeout->list);
-	os_free(timeout);
-}
-
-
-int eloop_cancel_timeout(eloop_timeout_handler handler,
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev;
-	int removed = 0;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		     eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		     user_data == ELOOP_ALL_CTX)) {
-			eloop_remove_timeout(timeout);
-			removed++;
-		}
-	}
-
-	return removed;
-}
-
-
-int eloop_cancel_timeout_one(eloop_timeout_handler handler,
-			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
-{
-	struct eloop_timeout *timeout, *prev;
-	int removed = 0;
-	struct os_time now;
-
-	os_get_time(&now);
-	remaining->sec = remaining->usec = 0;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data) &&
-		    (timeout->user_data == user_data)) {
-			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
-			eloop_remove_timeout(timeout);
-			break;
-		}
-	}
-	return removed;
-}
-
-
-int eloop_is_timeout_registered(eloop_timeout_handler handler,
-				void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *tmp;
-
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (tmp->handler == handler &&
-		    tmp->eloop_data == eloop_data &&
-		    tmp->user_data == user_data)
-			return 1;
-	}
-
-	return 0;
-}
-
-
-/* TODO: replace with suitable signal handler */
-#if 0
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-#endif
-
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	if (eloop.pending_terminate) {
-		eloop.pending_terminate = 0;
-	}
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.signals[i].user_data);
-		}
-	}
-}
-
-
-int eloop_register_signal(int sig, eloop_signal_handler handler,
-			  void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
-			       sizeof(struct eloop_signal));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-
-	/* TODO: register signal handler */
-
-	return 0;
-}
-
-
-int eloop_register_signal_terminate(eloop_signal_handler handler,
-				    void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	int ret = eloop_register_signal(SIGINT, handler, user_data);
-	if (ret == 0)
-		ret = eloop_register_signal(SIGTERM, handler, user_data);
-	return ret;
-#endif
-	return 0;
-}
-
-
-int eloop_register_signal_reconfig(eloop_signal_handler handler,
-				   void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	return eloop_register_signal(SIGHUP, handler, user_data);
-#endif
-	return 0;
-}
-
-
-void eloop_run(void)
-{
-	int i;
-	struct os_time tv, now;
-
-	while (!eloop.terminate &&
-		(!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0)) {
-		struct eloop_timeout *timeout;
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
-			else
-				tv.sec = tv.usec = 0;
-		}
-
-		/*
-		 * TODO: wait for any event (read socket ready, timeout (tv),
-		 * signal
-		 */
-		os_sleep(1, 0); /* just a dummy wait for testing */
-
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
-				void *eloop_data = timeout->eloop_data;
-				void *user_data = timeout->user_data;
-				eloop_timeout_handler handler =
-					timeout->handler;
-				eloop_remove_timeout(timeout);
-				handler(eloop_data, user_data);
-			}
-
-		}
-
-		eloop.reader_table_changed = 0;
-		for (i = 0; i < eloop.reader_count; i++) {
-			/*
-			 * TODO: call each handler that has pending data to
-			 * read
-			 */
-			if (0 /* TODO: eloop.readers[i].sock ready */) {
-				eloop.readers[i].handler(
-					eloop.readers[i].sock,
-					eloop.readers[i].eloop_data,
-					eloop.readers[i].user_data);
-				if (eloop.reader_table_changed)
-					break;
-			}
-		}
-	}
-}
-
-
-void eloop_terminate(void)
-{
-	eloop.terminate = 1;
-}
-
-
-void eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		eloop_remove_timeout(timeout);
-	}
-	os_free(eloop.readers);
-	os_free(eloop.signals);
-}
-
-
-int eloop_terminated(void)
-{
-	return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
-	/*
-	 * TODO: wait for the file descriptor to have something available for
-	 * reading
-	 */
-}
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index eda412f..de47fb2 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -31,7 +31,7 @@
 
 struct eloop_timeout {
 	struct dl_list list;
-	struct os_time time;
+	struct os_reltime time;
 	void *eloop_data;
 	void *user_data;
 	eloop_timeout_handler handler;
@@ -244,7 +244,7 @@
 	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	if (os_get_time(&timeout->time) < 0) {
+	if (os_get_reltime(&timeout->time) < 0) {
 		os_free(timeout);
 		return -1;
 	}
@@ -271,7 +271,7 @@
 
 	/* Maintain timeouts in order of increasing time */
 	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
+		if (os_reltime_before(&timeout->time, &tmp->time)) {
 			dl_list_add(tmp->list.prev, &timeout->list);
 			return 0;
 		}
@@ -313,13 +313,13 @@
 
 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 			     void *eloop_data, void *user_data,
-			     struct os_time *remaining)
+			     struct os_reltime *remaining)
 {
 	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	remaining->sec = remaining->usec = 0;
 
 	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
@@ -328,8 +328,8 @@
 		    (timeout->eloop_data == eloop_data) &&
 		    (timeout->user_data == user_data)) {
 			removed = 1;
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, remaining);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, remaining);
 			eloop_remove_timeout(timeout);
 			break;
 		}
@@ -354,6 +354,70 @@
 }
 
 
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+			  eloop_timeout_handler handler, void *eloop_data,
+			  void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&requested, &remaining)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+			    eloop_timeout_handler handler, void *eloop_data,
+			    void *user_data)
+{
+	struct os_reltime now, requested, remaining;
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data) {
+			requested.sec = req_secs;
+			requested.usec = req_usecs;
+			os_get_reltime(&now);
+			os_reltime_sub(&tmp->time, &now, &remaining);
+			if (os_reltime_before(&remaining, &requested)) {
+				eloop_cancel_timeout(handler, eloop_data,
+						     user_data);
+				eloop_register_timeout(requested.sec,
+						       requested.usec,
+						       handler, eloop_data,
+						       user_data);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
 /* TODO: replace with suitable signal handler */
 #if 0
 static void eloop_handle_signal(int sig)
@@ -468,7 +532,7 @@
 
 void eloop_run(void)
 {
-	struct os_time tv, now;
+	struct os_reltime tv, now;
 	DWORD count, ret, timeout_val, err;
 	size_t i;
 
@@ -480,9 +544,9 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
+			os_get_reltime(&now);
+			if (os_reltime_before(&now, &timeout->time))
+				os_reltime_sub(&timeout->time, &now, &tv);
 		}
 
 		count = 0;
@@ -521,8 +585,8 @@
 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
 					list);
 		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
+			os_get_reltime(&now);
+			if (!os_reltime_before(&now, &timeout->time)) {
 				void *eloop_data = timeout->eloop_data;
 				void *user_data = timeout->user_data;
 				eloop_timeout_handler handler =
diff --git a/src/utils/os.h b/src/utils/os.h
index ad20834..2e2350a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -23,6 +23,11 @@
 	os_time_t usec;
 };
 
+struct os_reltime {
+	os_time_t sec;
+	os_time_t usec;
+};
+
 /**
  * os_get_time - Get current time (sec, usec)
  * @t: Pointer to buffer for the time
@@ -30,21 +35,84 @@
  */
 int os_get_time(struct os_time *t);
 
+/**
+ * os_get_reltime - Get relative time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_reltime(struct os_reltime *t);
 
-/* Helper macros for handling struct os_time */
 
-#define os_time_before(a, b) \
-	((a)->sec < (b)->sec || \
-	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+/* Helpers for handling struct os_time */
 
-#define os_time_sub(a, b, res) do { \
-	(res)->sec = (a)->sec - (b)->sec; \
-	(res)->usec = (a)->usec - (b)->usec; \
-	if ((res)->usec < 0) { \
-		(res)->sec--; \
-		(res)->usec += 1000000; \
-	} \
-} while (0)
+static inline int os_time_before(struct os_time *a, struct os_time *b)
+{
+	return (a->sec < b->sec) ||
+	       (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_time_sub(struct os_time *a, struct os_time *b,
+			       struct os_time *res)
+{
+	res->sec = a->sec - b->sec;
+	res->usec = a->usec - b->usec;
+	if (res->usec < 0) {
+		res->sec--;
+		res->usec += 1000000;
+	}
+}
+
+
+/* Helpers for handling struct os_reltime */
+
+static inline int os_reltime_before(struct os_reltime *a,
+				    struct os_reltime *b)
+{
+	return (a->sec < b->sec) ||
+	       (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
+				  struct os_reltime *res)
+{
+	res->sec = a->sec - b->sec;
+	res->usec = a->usec - b->usec;
+	if (res->usec < 0) {
+		res->sec--;
+		res->usec += 1000000;
+	}
+}
+
+
+static inline void os_reltime_age(struct os_reltime *start,
+				  struct os_reltime *age)
+{
+	struct os_reltime now;
+
+	os_get_reltime(&now);
+	os_reltime_sub(&now, start, age);
+}
+
+
+static inline int os_reltime_expired(struct os_reltime *now,
+				     struct os_reltime *ts,
+				     os_time_t timeout_secs)
+{
+	struct os_reltime age;
+
+	os_reltime_sub(now, ts, &age);
+	return (age.sec > timeout_secs) ||
+	       (age.sec == timeout_secs && age.usec > 0);
+}
+
+
+static inline int os_reltime_initialized(struct os_reltime *t)
+{
+	return t->sec != 0 || t->usec != 0;
+}
+
 
 /**
  * os_mktime - Convert broken-down time into seconds since 1970-01-01
@@ -361,15 +429,6 @@
 int os_strncmp(const char *s1, const char *s2, size_t n);
 
 /**
- * os_strncpy - Copy a string
- * @dest: Destination
- * @src: Source
- * @n: Maximum number of characters to copy
- * Returns: dest
- */
-char * os_strncpy(char *dest, const char *src, size_t n);
-
-/**
  * os_strstr - Locate a substring
  * @haystack: String (haystack) to search from
  * @needle: Needle to search from haystack
@@ -465,9 +524,6 @@
 #ifndef os_strncmp
 #define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
 #endif
-#ifndef os_strncpy
-#define os_strncpy(d, s, n) strncpy((d), (s), (n))
-#endif
 #ifndef os_strrchr
 #define os_strrchr(s, c) strrchr((s), (c))
 #endif
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index e4b7fdb..2cb0d12 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -41,6 +41,17 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index cabf73b..228c472 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -26,6 +26,12 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	return -1;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 10b9e0d..fa67fdf 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -17,10 +17,10 @@
 #endif /* ANDROID */
 
 #include "os.h"
+#include "common.h"
 
 #ifdef WPA_TRACE
 
-#include "common.h"
 #include "wpa_debug.h"
 #include "trace.h"
 #include "list.h"
@@ -60,6 +60,43 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+#if defined(CLOCK_BOOTTIME)
+	static clockid_t clock_id = CLOCK_BOOTTIME;
+#elif defined(CLOCK_MONOTONIC)
+	static clockid_t clock_id = CLOCK_MONOTONIC;
+#else
+	static clockid_t clock_id = CLOCK_REALTIME;
+#endif
+	struct timespec ts;
+	int res;
+
+	while (1) {
+		res = clock_gettime(clock_id, &ts);
+		if (res == 0) {
+			t->sec = ts.tv_sec;
+			t->usec = ts.tv_nsec / 1000;
+			return 0;
+		}
+		switch (clock_id) {
+#ifdef CLOCK_BOOTTIME
+		case CLOCK_BOOTTIME:
+			clock_id = CLOCK_MONOTONIC;
+			break;
+#endif
+#ifdef CLOCK_MONOTONIC
+		case CLOCK_MONOTONIC:
+			clock_id = CLOCK_REALTIME;
+			break;
+#endif
+		case CLOCK_REALTIME:
+			return -1;
+		}
+	}
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
@@ -268,7 +305,7 @@
 	struct __user_cap_header_struct header;
 	struct __user_cap_data_struct cap;
 
-	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+	setgroups(ARRAY_SIZE(groups), groups);
 
 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
 
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 163cebe..1cfa7a5 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -47,6 +47,17 @@
 }
 
 
+int os_get_reltime(struct os_reltime *t)
+{
+	/* consider using performance counters or so instead */
+	struct os_time now;
+	int res = os_get_time(&now);
+	t->sec = now.sec;
+	t->usec = now.usec;
+	return res;
+}
+
+
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t)
 {
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index 08510d0..ee90d25 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -485,17 +485,15 @@
 
 /**
  * scard_init - Initialize SIM/USIM connection using PC/SC
- * @sim_type: Allowed SIM types (SIM, USIM, or both)
  * @reader: Reader name prefix to search for
  * Returns: Pointer to private data structure, or %NULL on failure
  *
  * This function is used to initialize SIM/USIM connection. PC/SC is used to
- * open connection to the SIM/USIM card and the card is verified to support the
- * selected sim_type. In addition, local flag is set if a PIN is needed to
- * access some of the card functions. Once the connection is not needed
- * anymore, scard_deinit() can be used to close it.
+ * open connection to the SIM/USIM card. In addition, local flag is set if a
+ * PIN is needed to access some of the card functions. Once the connection is
+ * not needed anymore, scard_deinit() can be used to close it.
  */
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
+struct scard_data * scard_init(const char *reader)
 {
 	long ret;
 	unsigned long len, pos;
@@ -612,20 +610,14 @@
 
 	blen = sizeof(buf);
 
-	scard->sim_type = SCARD_GSM_SIM;
-	if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
-		wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
-		if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
-				       SCARD_USIM, NULL, 0)) {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
-			if (sim_type == SCARD_USIM_ONLY)
-				goto failed;
-			wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
-			scard->sim_type = SCARD_GSM_SIM;
-		} else {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
-			scard->sim_type = SCARD_USIM;
-		}
+	wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
+	if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
+			       SCARD_USIM, NULL, 0)) {
+		wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported. Trying to use GSM SIM");
+		scard->sim_type = SCARD_GSM_SIM;
+	} else {
+		wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+		scard->sim_type = SCARD_USIM;
 	}
 
 	if (scard->sim_type == SCARD_GSM_SIM) {
diff --git a/src/utils/pcsc_funcs.h b/src/utils/pcsc_funcs.h
index b4ebc99..eacd2a2 100644
--- a/src/utils/pcsc_funcs.h
+++ b/src/utils/pcsc_funcs.h
@@ -9,15 +9,8 @@
 #ifndef PCSC_FUNCS_H
 #define PCSC_FUNCS_H
 
-typedef enum {
-	SCARD_GSM_SIM_ONLY,
-	SCARD_USIM_ONLY,
-	SCARD_TRY_BOTH
-} scard_sim_type;
-
-
 #ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
+struct scard_data * scard_init(const char *reader);
 void scard_deinit(struct scard_data *scard);
 
 int scard_set_pin(struct scard_data *scard, const char *pin);
@@ -34,7 +27,7 @@
 
 #else /* PCSC_FUNCS */
 
-#define scard_init(s, r) NULL
+#define scard_init(r) NULL
 #define scard_deinit(s) do { } while (0)
 #define scard_set_pin(s, p) -1
 #define scard_get_imsi(s, i, l) -1
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 38ea8aa..647f6b4 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -375,19 +375,19 @@
 #endif /* CONFIG_ANDROID_LOG */
 }
 
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
 {
 	_wpa_hexdump(level, title, buf, len, 1);
 }
 
 
-void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
 {
 	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
 }
 
 
-static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
 			       size_t len, int show)
 {
 	size_t i, llen;
@@ -407,7 +407,7 @@
 			/* can do ascii processing in userspace */
 			for (i = 0; i < len; i++)
 				fprintf(wpa_debug_tracing_file,
-					" %02x", buf[i]);
+					" %02x", pos[i]);
 		}
 		fflush(wpa_debug_tracing_file);
 	}
@@ -495,13 +495,14 @@
 }
 
 
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump_ascii(int level, const char *title, const void *buf,
+		       size_t len)
 {
 	_wpa_hexdump_ascii(level, title, buf, len, 1);
 }
 
 
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 			   size_t len)
 {
 	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
@@ -595,10 +596,14 @@
 {
 	va_list ap;
 	char *buf;
-	const int buflen = 2048;
+	int buflen;
 	int len;
 	char prefix[130];
 
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
@@ -629,12 +634,16 @@
 {
 	va_list ap;
 	char *buf;
-	const int buflen = 2048;
+	int buflen;
 	int len;
 
 	if (!wpa_msg_cb)
 		return;
 
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
@@ -653,9 +662,13 @@
 {
 	va_list ap;
 	char *buf;
-	const int buflen = 2048;
+	int buflen;
 	int len;
 
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
@@ -676,9 +689,13 @@
 {
 	va_list ap;
 	char *buf;
-	const int buflen = 2048;
+	int buflen;
 	int len;
 
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
@@ -711,9 +728,13 @@
 {
 	va_list ap;
 	char *buf;
-	const int buflen = 2048;
+	int buflen;
 	int len;
 
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 2ed1bd8..50e8ae9 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -11,6 +11,10 @@
 
 #include "wpabuf.h"
 
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
 /* Debugging function - conditional printf and hex dump. Driver wrappers can
  * use these for debugging purposes. */
 
@@ -77,7 +81,7 @@
  * output may be directed to stdout, stderr, and/or syslog based on
  * configuration. The contents of buf is printed out has hex dump.
  */
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+void wpa_hexdump(int level, const char *title, const void *buf, size_t len);
 
 static inline void wpa_hexdump_buf(int level, const char *title,
 				   const struct wpabuf *buf)
@@ -99,7 +103,7 @@
  * like wpa_hexdump(), but by default, does not include secret keys (passwords,
  * etc.) in debug output.
  */
-void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len);
 
 static inline void wpa_hexdump_buf_key(int level, const char *title,
 				       const struct wpabuf *buf)
@@ -121,7 +125,7 @@
  * the hex numbers and ASCII characters (for printable range) are shown. 16
  * bytes per line will be shown.
  */
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii(int level, const char *title, const void *buf,
 		       size_t len);
 
 /**
@@ -138,7 +142,7 @@
  * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
  * default, does not include secret keys (passwords, etc.) in debug output.
  */
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 			   size_t len);
 
 /*
diff --git a/src/wps/Makefile b/src/wps/Makefile
index 9c41962..adfd3df 100644
--- a/src/wps/Makefile
+++ b/src/wps/Makefile
@@ -2,7 +2,7 @@
 	@echo Nothing to be made.
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 
 install:
 	@echo Nothing to be made.
diff --git a/src/wps/http_server.c b/src/wps/http_server.c
index 6ca3214..06c8bee 100644
--- a/src/wps/http_server.c
+++ b/src/wps/http_server.c
@@ -232,6 +232,7 @@
 {
 	struct sockaddr_in sin;
 	struct http_server *srv;
+	int on = 1;
 
 	srv = os_zalloc(sizeof(*srv));
 	if (srv == NULL)
@@ -242,6 +243,9 @@
 	srv->fd = socket(AF_INET, SOCK_STREAM, 0);
 	if (srv->fd < 0)
 		goto fail;
+
+	setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
 	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
 		goto fail;
 	if (port < 0)
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index ad4f4a1..b51d975 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -67,8 +67,6 @@
 	int timeout_seconds;            /* 0 or total duration timeout period */
 
 	/* dynamically used information follows */
-	int sd_registered;      /* nonzero if we need to unregister socket */
-	int to_registered;      /* nonzero if we need to unregister timeout */
 
 	int got_hdr;            /* nonzero when header is finalized */
 	char hdr[HTTPREAD_HEADER_MAX_SIZE+1];   /* headers stored here */
@@ -129,19 +127,6 @@
 }
 
 
-/* convert hex to binary
- * Requires that c have been previously tested true with isxdigit().
- */
-static int hex_value(int c)
-{
-	if (isdigit(c))
-		return c - '0';
-	if (islower(c))
-		return 10 + c - 'a';
-	return 10 + c - 'A';
-}
-
-
 static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
 
 /* httpread_destroy -- if h is non-NULL, clean up
@@ -156,12 +141,8 @@
 	if (!h)
 		return;
 
-	if (h->to_registered)
-		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-	h->to_registered = 0;
-	if (h->sd_registered)
-		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-	h->sd_registered = 0;
+	eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+	eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
 	os_free(h->body);
 	os_free(h->uri);
 	os_memset(h, 0, sizeof(*h));  /* aid debugging */
@@ -176,7 +157,6 @@
 {
 	struct httpread *h = user_ctx;
 	wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
-	h->to_registered = 0;   /* is self-cancelling */
 	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
 }
 
@@ -295,8 +275,7 @@
 			int c = *rawuri;
 			if (c == '%' &&
 			    isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
-				*uri++ = (hex_value(rawuri[1]) << 4) |
-					hex_value(rawuri[2]);
+				*uri++ = hex2byte(rawuri + 1);
 				rawuri += 3;
 			} else {
 				*uri++ = c;
@@ -703,15 +682,11 @@
 	 * and just in case somehow we don't get destroyed right away,
 	 * unregister now.
 	 */
-	if (h->sd_registered)
-		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-	h->sd_registered = 0;
+	eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
 	/* The application can destroy us whenever they feel like...
 	 * cancel timeout.
 	 */
-	if (h->to_registered)
-		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-	h->to_registered = 0;
+	eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
 	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
 }
 
@@ -749,21 +724,17 @@
 	h->max_bytes = max_bytes;
 	h->timeout_seconds = timeout_seconds;
 
-	if (timeout_seconds > 0) {
-		if (eloop_register_timeout(timeout_seconds, 0,
-					   httpread_timeout_handler,
-					   NULL, h)) {
-			/* No way to recover (from malloc failure) */
-			goto fail;
-		}
-		h->to_registered = 1;
+	if (timeout_seconds > 0 &&
+	    eloop_register_timeout(timeout_seconds, 0,
+				   httpread_timeout_handler, NULL, h)) {
+		/* No way to recover (from malloc failure) */
+		goto fail;
 	}
 	if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
 				NULL, h)) {
 		/* No way to recover (from malloc failure) */
 		goto fail;
 	}
-	h->sd_registered = 1;
 	return h;
 
 fail:
diff --git a/src/wps/ndef.c b/src/wps/ndef.c
index 96685d2..2b35064 100644
--- a/src/wps/ndef.c
+++ b/src/wps/ndef.c
@@ -30,6 +30,7 @@
 };
 
 static char wifi_handover_type[] = "application/vnd.wfa.wsc";
+static char p2p_handover_type[] = "application/vnd.wfa.p2p";
 
 static int ndef_parse_record(const u8 *data, u32 size,
 			     struct ndef_record *record)
@@ -170,85 +171,26 @@
 }
 
 
-struct wpabuf * ndef_build_wifi_hc(int begin)
+static int p2p_filter(struct ndef_record *record)
 {
-	struct wpabuf *hc, *carrier;
-
-	carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
-	if (carrier == NULL)
-		return NULL;
-	wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
-	wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
-	wpabuf_put_str(carrier, wifi_handover_type);
-
-	hc = ndef_build_record((begin ? FLAG_MESSAGE_BEGIN : 0) |
-			       FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
-			       "0", 1, carrier);
-	wpabuf_free(carrier);
-
-	return hc;
+	if (record->type_length != os_strlen(p2p_handover_type))
+		return 0;
+	if (os_memcmp(record->type, p2p_handover_type,
+		      os_strlen(p2p_handover_type)) != 0)
+		return 0;
+	return 1;
 }
 
 
-struct wpabuf * ndef_build_wifi_hr(void)
+struct wpabuf * ndef_parse_p2p(const struct wpabuf *buf)
 {
-	struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
-	struct wpabuf *hc;
+	return ndef_parse_records(buf, p2p_filter);
+}
 
-	rn = wpabuf_alloc(2);
-	if (rn == NULL)
-		return NULL;
-	wpabuf_put_be16(rn, os_random() & 0xffff);
 
-	cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
-			       NULL, 0, rn);
-	wpabuf_free(rn);
-
-	if (cr == NULL)
-		return NULL;
-
-	ac_payload = wpabuf_alloc(4);
-	if (ac_payload == NULL) {
-		wpabuf_free(cr);
-		return NULL;
-	}
-	wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
-	wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
-	wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
-	wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
-
-	ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
-			       NULL, 0, ac_payload);
-	wpabuf_free(ac_payload);
-	if (ac == NULL) {
-		wpabuf_free(cr);
-		return NULL;
-	}
-
-	hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
-	if (hr_payload == NULL) {
-		wpabuf_free(cr);
-		wpabuf_free(ac);
-		return NULL;
-	}
-
-	wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
-	wpabuf_put_buf(hr_payload, cr);
-	wpabuf_put_buf(hr_payload, ac);
-	wpabuf_free(cr);
-	wpabuf_free(ac);
-
-	hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
-			       NULL, 0, hr_payload);
-	wpabuf_free(hr_payload);
-	if (hr == NULL)
-		return NULL;
-
-	hc = ndef_build_wifi_hc(0);
-	if (hc == NULL) {
-		wpabuf_free(hr);
-		return NULL;
-	}
-
-	return wpabuf_concat(hr, hc);
+struct wpabuf * ndef_build_p2p(const struct wpabuf *buf)
+{
+	return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
+				 FLAG_TNF_RFC2046, p2p_handover_type,
+				 os_strlen(p2p_handover_type), NULL, 0, buf);
 }
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 22d7eea..3d019f1 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -18,6 +18,7 @@
 #ifdef CONFIG_WPS_TESTING
 int wps_version_number = 0x20;
 int wps_testing_dummy_cred = 0;
+int wps_corrupt_pkhash = 0;
 #endif /* CONFIG_WPS_TESTING */
 
 
@@ -58,6 +59,10 @@
 	}
 
 #ifdef CONFIG_WPS_NFC
+	if (cfg->pin == NULL &&
+	    cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+		data->dev_pw_id = cfg->dev_pw_id;
+
 	if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
 		/* Keep AP PIN as alternative Device Password */
 		data->alt_dev_pw_id = data->dev_pw_id;
@@ -133,6 +138,12 @@
 	data->use_psk_key = cfg->use_psk_key;
 	data->pbc_in_m1 = cfg->pbc_in_m1;
 
+	if (cfg->peer_pubkey_hash) {
+		os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash,
+			  WPS_OOB_PUBKEY_HASH_LEN);
+		data->peer_pubkey_hash_set = 1;
+	}
+
 	return data;
 }
 
@@ -168,7 +179,6 @@
 	wps_device_data_free(&data->peer_dev);
 	os_free(data->new_ap_settings);
 	dh5_free(data->dh_ctx);
-	os_free(data->nfc_pw_token);
 	os_free(data);
 }
 
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 15137a8..192d283 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -42,7 +42,6 @@
  * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
  *	this may be %NULL, if not used
  * @cred_attr_len: Length of cred_attr in octets
- * @ap_channel: AP channel
  */
 struct wps_credential {
 	u8 ssid[32];
@@ -55,7 +54,6 @@
 	u8 mac_addr[ETH_ALEN];
 	const u8 *cred_attr;
 	size_t cred_attr_len;
-	u16 ap_channel;
 };
 
 #define WPS_DEV_TYPE_LEN 8
@@ -183,6 +181,11 @@
 	 * PBC with the AP.
 	 */
 	int pbc_in_m1;
+
+	/**
+	 * peer_pubkey_hash - Peer public key hash or %NULL if not known
+	 */
+	const u8 *peer_pubkey_hash;
 };
 
 struct wps_data * wps_init(const struct wps_config *cfg);
@@ -665,6 +668,16 @@
 	u16 auth_types;
 
 	/**
+	 * encr_types - Current AP encryption type (WPS_ENCR_*)
+	 */
+	u16 ap_encr_type;
+
+	/**
+	 * ap_auth_type - Current AP authentication types (WPS_AUTH_*)
+	 */
+	u16 ap_auth_type;
+
+	/**
 	 * network_key - The current Network Key (PSK) or %NULL to generate new
 	 *
 	 * If %NULL, Registrar will generate per-device PSK. In addition, AP
@@ -801,7 +814,8 @@
 			    struct wps_credential *cred);
 int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
 				   const u8 *pubkey_hash, u16 pw_id,
-				   const u8 *dev_pw, size_t dev_pw_len);
+				   const u8 *dev_pw, size_t dev_pw_len,
+				   int pk_hash_provided_oob);
 int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
 					 const u8 *oob_dev_pw,
 					 size_t oob_dev_pw_len);
@@ -815,7 +829,8 @@
 int wps_pin_str_valid(const char *pin);
 void wps_free_pending_msgs(struct upnp_pending_message *msgs);
 
-struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
+				 int channel);
 int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
 int wps_attr_text(struct wpabuf *data, char *buf, char *end);
 const char * wps_ei_str(enum wps_error_indication ei);
@@ -839,6 +854,9 @@
 					      struct wps_credential *cred);
 struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
 					const u8 *addr);
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+					struct wps_context *wps, const u8 *uuid,
+					const u8 *addr, struct wpabuf *pubkey);
 
 int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
 char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
@@ -850,15 +868,27 @@
 				       const struct wpabuf *dev_pw);
 struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
 				    struct wpabuf *dev_pw);
+int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey);
 struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 				  struct wpabuf **privkey,
 				  struct wpabuf **dev_pw);
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey);
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey,
+					   const u8 *bssid, int freq);
+struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
+					       struct wpabuf *nfc_dh_pubkey);
+struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
+					       int nfc_dev_pw_id,
+					       struct wpabuf *nfc_dh_pubkey,
+					       struct wpabuf *nfc_dev_pw);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
 struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi_hc(int begin);
-struct wpabuf * ndef_build_wifi_hr(void);
+struct wpabuf * ndef_parse_p2p(const struct wpabuf *buf);
+struct wpabuf * ndef_build_p2p(const struct wpabuf *buf);
 
 #ifdef CONFIG_WPS_STRICT
 int wps_validate_beacon(const struct wpabuf *wps_ie);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index ac9bb1e..62d0feb 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -38,8 +38,15 @@
 		wps->wps->dh_ctx = NULL;
 		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
 #ifdef CONFIG_WPS_NFC
-	} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
-		   wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+	} else if ((wps->dev_pw_id >= 0x10 ||
+		    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
+		   (wps->wps->ap ||
+		    (wps->wps->ap_nfc_dh_pubkey &&
+		     wps->wps->ap_nfc_dev_pw_id ==
+		     DEV_PW_NFC_CONNECTION_HANDOVER &&
+		     wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
+		   (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
+		    wps->wps->ap_nfc_dh_pubkey)) {
 		wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
 		if (wps->wps->ap_nfc_dh_privkey == NULL) {
 			wpa_printf(MSG_DEBUG,
@@ -118,6 +125,8 @@
 
 int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
 {
+	if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
+		return -1;
 	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
 	wpabuf_put_be16(msg, ATTR_UUID_E);
 	wpabuf_put_be16(msg, WPS_UUID_LEN);
@@ -183,6 +192,8 @@
 	 * backwards compatibility reasons. The real version negotiation is
 	 * done with Version2.
 	 */
+	if (wpabuf_tailroom(msg) < 5)
+		return -1;
 	wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
 	wpabuf_put_be16(msg, ATTR_VERSION);
 	wpabuf_put_be16(msg, 1);
@@ -197,6 +208,15 @@
 #ifdef CONFIG_WPS2
 	u8 *len;
 
+#ifdef CONFIG_WPS_TESTING
+	if (WPS_VERSION == 0x10)
+		return 0;
+#endif /* CONFIG_WPS_TESTING */
+
+	if (wpabuf_tailroom(msg) <
+	    7 + 3 + (req_to_enroll ? 3 : 0) +
+	    (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
+		return -1;
 	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
 	len = wpabuf_put(msg, 2); /* to be filled */
 	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
@@ -230,6 +250,8 @@
 
 #ifdef CONFIG_WPS_TESTING
 	if (WPS_VERSION > 0x20) {
+		if (wpabuf_tailroom(msg) < 5)
+			return -1;
 		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
 			   "attribute");
 		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
@@ -372,15 +394,31 @@
 	const u8 *addr[1];
 	u8 pubkey_hash[WPS_HASH_LEN];
 
+	wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password (dev_pw_id=%u)",
+		   dev_pw_id);
 	addr[0] = wpabuf_head(pubkey);
 	hash_len = wpabuf_len(pubkey);
 	sha256_vector(1, addr, &hash_len, pubkey_hash);
+#ifdef CONFIG_WPS_TESTING
+	if (wps_corrupt_pkhash) {
+		wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
+			    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+		wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash");
+		pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++;
+	}
+#endif /* CONFIG_WPS_TESTING */
 
 	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
 	wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+	wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+		    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_be16(msg, dev_pw_id);
-	wpabuf_put_data(msg, dev_pw, dev_pw_len);
+	if (dev_pw) {
+		wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
+				dev_pw, dev_pw_len);
+		wpabuf_put_data(msg, dev_pw, dev_pw_len);
+	}
 
 	return 0;
 }
@@ -428,3 +466,23 @@
 	wpabuf_put_data(msg, addr, ETH_ALEN);
 	return 0;
 }
+
+
+int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", rf_bands);
+	wpabuf_put_be16(msg, ATTR_RF_BANDS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, rf_bands);
+	return 0;
+}
+
+
+int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * AP Channel (%u)", ap_channel);
+	wpabuf_put_be16(msg, ATTR_AP_CHANNEL);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, ap_channel);
+	return 0;
+}
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 3999b1b..1ebcfe9 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -75,7 +75,7 @@
 	const u8 *end = pos + len;
 	u8 id, elen;
 
-	while (pos + 2 < end) {
+	while (pos + 2 <= end) {
 		id = *pos++;
 		elen = *pos++;
 		if (pos + elen > end)
@@ -263,10 +263,13 @@
 		attr->dev_password_id = pos;
 		break;
 	case ATTR_OOB_DEVICE_PASSWORD:
-		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
-		    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
 		    len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
-		    WPS_OOB_DEVICE_PASSWORD_LEN) {
+		    WPS_OOB_DEVICE_PASSWORD_LEN ||
+		    (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+		     WPS_OOB_DEVICE_PASSWORD_MIN_LEN &&
+		     WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) !=
+		     DEV_PW_NFC_CONNECTION_HANDOVER)) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
 				   "Password length %u", len);
 			return -1;
@@ -410,22 +413,6 @@
 		}
 		attr->mac_addr = pos;
 		break;
-	case ATTR_KEY_PROVIDED_AUTO:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
-				   "Automatically length %u", len);
-			return -1;
-		}
-		attr->key_prov_auto = pos;
-		break;
-	case ATTR_802_1X_ENABLED:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
-				   "length %u", len);
-			return -1;
-		}
-		attr->dot1x_enabled = pos;
-		break;
 	case ATTR_SELECTED_REGISTRAR:
 		if (len != 1) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
@@ -497,14 +484,6 @@
 		attr->network_key = pos;
 		attr->network_key_len = len;
 		break;
-	case ATTR_EAP_TYPE:
-		attr->eap_type = pos;
-		attr->eap_type_len = len;
-		break;
-	case ATTR_EAP_IDENTITY:
-		attr->eap_identity = pos;
-		attr->eap_identity_len = len;
-		break;
 	case ATTR_AP_SETUP_LOCKED:
 		if (len != 1) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
index 88e51a4..eeb08d1 100644
--- a/src/wps/wps_attr_parse.h
+++ b/src/wps/wps_attr_parse.h
@@ -47,8 +47,6 @@
 	const u8 *network_idx; /* 1 octet */
 	const u8 *network_key_idx; /* 1 octet */
 	const u8 *mac_addr; /* ETH_ALEN (6) octets */
-	const u8 *key_prov_auto; /* 1 octet (Bool) */
-	const u8 *dot1x_enabled; /* 1 octet (Bool) */
 	const u8 *selected_registrar; /* 1 octet (Bool) */
 	const u8 *request_type; /* 1 octet */
 	const u8 *response_type; /* 1 octet */
@@ -77,10 +75,6 @@
 	size_t ssid_len;
 	const u8 *network_key; /* <= 64 octets */
 	size_t network_key_len;
-	const u8 *eap_type; /* <= 8 octets */
-	size_t eap_type_len;
-	const u8 *eap_identity; /* <= 64 octets */
-	size_t eap_identity_len;
 	const u8 *authorized_macs; /* <= 30 octets */
 	size_t authorized_macs_len;
 	const u8 *sec_dev_type_list; /* <= 128 octets */
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index b81f106..5266620 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -207,70 +207,6 @@
 }
 
 
-static int wps_process_cred_eap_type(struct wps_credential *cred,
-				     const u8 *eap_type, size_t eap_type_len)
-{
-	if (eap_type == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_eap_identity(struct wps_credential *cred,
-					 const u8 *identity,
-					 size_t identity_len)
-{
-	if (identity == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
-			  identity, identity_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
-					  const u8 *key_prov_auto)
-{
-	if (key_prov_auto == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
-		   *key_prov_auto);
-
-	return 0;
-}
-
-
-static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
-					   const u8 *dot1x_enabled)
-{
-	if (dot1x_enabled == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
-
-	return 0;
-}
-
-
-static int wps_process_cred_ap_channel(struct wps_credential *cred,
-				       const u8 *ap_channel)
-{
-	if (ap_channel == NULL)
-		return 0; /* optional attribute */
-
-	cred->ap_channel = WPA_GET_BE16(ap_channel);
-	wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
-
-	return 0;
-}
-
-
 static int wps_workaround_cred_key(struct wps_credential *cred)
 {
 	if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
@@ -310,14 +246,7 @@
 	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
 	    wps_process_cred_network_key(cred, attr->network_key,
 					 attr->network_key_len) ||
-	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
-	    wps_process_cred_eap_type(cred, attr->eap_type,
-				      attr->eap_type_len) ||
-	    wps_process_cred_eap_identity(cred, attr->eap_identity,
-					  attr->eap_identity_len) ||
-	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
-	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
-	    wps_process_cred_ap_channel(cred, attr->ap_channel))
+	    wps_process_cred_mac_addr(cred, attr->mac_addr))
 		return -1;
 
 	return wps_workaround_cred_key(cred);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 4b431ad..abf3a4f 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -9,6 +9,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_common.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
 #include "crypto/dh_group5.h"
@@ -16,6 +18,7 @@
 #include "crypto/sha256.h"
 #include "crypto/random.h"
 #include "wps_i.h"
+#include "wps_dev_attr.h"
 
 
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
@@ -349,7 +352,8 @@
 
 #ifdef CONFIG_WPS_OOB
 
-struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
+				 int channel)
 {
 	struct wps_data data;
 	struct wpabuf *plain;
@@ -365,8 +369,10 @@
 	data.wps = wps;
 	data.auth_type = wps->auth_types;
 	data.encr_type = wps->encr_types;
-	if (wps_build_version(plain) ||
-	    wps_build_cred(&data, plain) ||
+	if (wps_build_cred(&data, plain) ||
+	    (rf_band && wps_build_rf_bands_attr(plain, rf_band)) ||
+	    (channel && wps_build_ap_channel(plain, channel)) ||
+	    wps_build_mac_addr(plain, wps->dev.mac_addr) ||
 	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
 		os_free(data.new_psk);
 		wpabuf_free(plain);
@@ -412,8 +418,7 @@
 	if (data == NULL)
 		return NULL;
 
-	if (wps_build_version(data) ||
-	    wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+	if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
 				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
 	    wps_build_wfa_ext(data, 0, NULL, 0)) {
 		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
@@ -636,12 +641,36 @@
 }
 
 
+int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
+{
+	struct wpabuf *priv = NULL, *pub = NULL;
+	void *dh_ctx;
+
+	dh_ctx = dh5_init(&priv, &pub);
+	if (dh_ctx == NULL)
+		return -1;
+	pub = wpabuf_zeropad(pub, 192);
+	if (pub == NULL) {
+		wpabuf_free(priv);
+		return -1;
+	}
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
+	dh5_free(dh_ctx);
+
+	wpabuf_free(*pubkey);
+	*pubkey = pub;
+	wpabuf_free(*privkey);
+	*privkey = priv;
+
+	return 0;
+}
+
+
 struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 				  struct wpabuf **privkey,
 				  struct wpabuf **dev_pw)
 {
-	struct wpabuf *priv = NULL, *pub = NULL, *pw;
-	void *dh_ctx;
+	struct wpabuf *pw;
 	u16 val;
 
 	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
@@ -655,22 +684,223 @@
 		return NULL;
 	}
 
-	dh_ctx = dh5_init(&priv, &pub);
-	if (dh_ctx == NULL) {
+	if (wps_nfc_gen_dh(pubkey, privkey) < 0) {
 		wpabuf_free(pw);
 		return NULL;
 	}
-	dh5_free(dh_ctx);
 
 	*id = 0x10 + val % 0xfff0;
-	wpabuf_free(*pubkey);
-	*pubkey = pub;
-	wpabuf_free(*privkey);
-	*privkey = priv;
 	wpabuf_free(*dev_pw);
 	*dev_pw = pw;
 
 	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
 }
 
+
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey)
+{
+	struct wpabuf *msg;
+	void *len;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover request");
+
+	if (nfc_dh_pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+			   "configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+	len = wpabuf_put(msg, 2);
+
+	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+				 nfc_dh_pubkey, NULL, 0) ||
+	    wps_build_uuid_e(msg, ctx->uuid) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+	return msg;
+}
+
+
+static int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select",
+			  wps->ssid, wps->ssid_len);
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, wps->ssid_len);
+	wpabuf_put_data(msg, wps->ssid, wps->ssid_len);
+	return 0;
+}
+
+
+static int wps_build_ap_freq(struct wpabuf *msg, int freq)
+{
+	enum hostapd_hw_mode mode;
+	u8 channel, rf_band;
+	u16 ap_channel;
+
+	if (freq <= 0)
+		return 0;
+
+	mode = ieee80211_freq_to_chan(freq, &channel);
+	if (mode == NUM_HOSTAPD_MODES)
+		return 0; /* Unknown channel */
+
+	if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B)
+		rf_band = WPS_RF_24GHZ;
+	else if (mode == HOSTAPD_MODE_IEEE80211A)
+		rf_band = WPS_RF_50GHZ;
+	else
+		return 0; /* Unknown band */
+	ap_channel = channel;
+
+	if (wps_build_rf_bands_attr(msg, rf_band) ||
+	    wps_build_ap_channel(msg, ap_channel))
+		return -1;
+
+	return 0;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey,
+					   const u8 *bssid, int freq)
+{
+	struct wpabuf *msg;
+	void *len;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover select");
+
+	if (nfc_dh_pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+			   "configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+	len = wpabuf_put(msg, 2);
+
+	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+				 nfc_dh_pubkey, NULL, 0) ||
+	    wps_build_ssid(msg, ctx) ||
+	    wps_build_ap_freq(msg, freq) ||
+	    (bssid && wps_build_mac_addr(msg, bssid)) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+	return msg;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
+					       struct wpabuf *nfc_dh_pubkey)
+{
+	struct wpabuf *msg;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover request (P2P)");
+
+	if (nfc_dh_pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+
+	if (wps_build_manufacturer(&ctx->dev, msg) ||
+	    wps_build_model_name(&ctx->dev, msg) ||
+	    wps_build_model_number(&ctx->dev, msg) ||
+	    wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+				 nfc_dh_pubkey, NULL, 0) ||
+	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
+	    wps_build_serial_number(&ctx->dev, msg) ||
+	    wps_build_uuid_e(msg, ctx->uuid) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
+					       int nfc_dev_pw_id,
+					       struct wpabuf *nfc_dh_pubkey,
+					       struct wpabuf *nfc_dev_pw)
+{
+	struct wpabuf *msg;
+	const u8 *dev_pw;
+	size_t dev_pw_len;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover select (P2P)");
+
+	if (nfc_dh_pubkey == NULL ||
+	    (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
+	     nfc_dev_pw == NULL)) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+			   "configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+
+	if (nfc_dev_pw) {
+		dev_pw = wpabuf_head(nfc_dev_pw);
+		dev_pw_len = wpabuf_len(nfc_dev_pw);
+	} else {
+		dev_pw = NULL;
+		dev_pw_len = 0;
+	}
+
+	if (wps_build_manufacturer(&ctx->dev, msg) ||
+	    wps_build_model_name(&ctx->dev, msg) ||
+	    wps_build_model_number(&ctx->dev, msg) ||
+	    wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey,
+				 dev_pw, dev_pw_len) ||
+	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
+	    wps_build_serial_number(&ctx->dev, msg) ||
+	    wps_build_uuid_e(msg, ctx->uuid) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 3421ac5..6f8a49f 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -13,6 +13,7 @@
 
 extern int wps_version_number;
 extern int wps_testing_dummy_cred;
+extern int wps_corrupt_pkhash;
 #define WPS_VERSION wps_version_number
 
 #else /* CONFIG_WPS_TESTING */
@@ -155,7 +156,8 @@
 	DEV_PW_MACHINE_SPECIFIED = 0x0002,
 	DEV_PW_REKEY = 0x0003,
 	DEV_PW_PUSHBUTTON = 0x0004,
-	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+	DEV_PW_REGISTRAR_SPECIFIED = 0x0005,
+	DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007
 };
 
 /* Message Type */
@@ -215,7 +217,9 @@
 	WPS_CFG_SETUP_LOCKED = 15,
 	WPS_CFG_MSG_TIMEOUT = 16,
 	WPS_CFG_REG_SESS_TIMEOUT = 17,
-	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
+	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18,
+	WPS_CFG_60G_CHAN_NOT_SUPPORTED = 19,
+	WPS_CFG_PUBLIC_KEY_HASH_MISMATCH = 20
 };
 
 /* Vendor specific Error Indication for WPS event messages */
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 1b12b5a..0d01211 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -85,8 +85,7 @@
 }
 
 
-static int wps_build_serial_number(struct wps_device_data *dev,
-				   struct wpabuf *msg)
+int wps_build_serial_number(struct wps_device_data *dev, struct wpabuf *msg)
 {
 	size_t len;
 	wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
@@ -220,11 +219,7 @@
 int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
 		       u8 rf_band)
 {
-	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", dev->rf_bands);
-	wpabuf_put_be16(msg, ATTR_RF_BANDS);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, rf_band ? rf_band : dev->rf_bands);
-	return 0;
+	return wps_build_rf_bands_attr(msg, rf_band ? rf_band : dev->rf_bands);
 }
 
 
@@ -409,25 +404,6 @@
 }
 
 
-void wps_device_data_dup(struct wps_device_data *dst,
-			 const struct wps_device_data *src)
-{
-	if (src->device_name)
-		dst->device_name = os_strdup(src->device_name);
-	if (src->manufacturer)
-		dst->manufacturer = os_strdup(src->manufacturer);
-	if (src->model_name)
-		dst->model_name = os_strdup(src->model_name);
-	if (src->model_number)
-		dst->model_number = os_strdup(src->model_number);
-	if (src->serial_number)
-		dst->serial_number = os_strdup(src->serial_number);
-	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
-	dst->os_version = src->os_version;
-	dst->rf_bands = src->rf_bands;
-}
-
-
 void wps_device_data_free(struct wps_device_data *dev)
 {
 	os_free(dev->device_name);
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index 0158cdc..c9034ad 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -14,6 +14,7 @@
 int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_serial_number(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
@@ -29,8 +30,6 @@
 			     struct wps_parse_attr *attr);
 int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
 int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
-void wps_device_data_dup(struct wps_device_data *dst,
-			 const struct wps_device_data *src);
 void wps_device_data_free(struct wps_device_data *dev);
 int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index d02ba30..70d6a17 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -243,54 +243,30 @@
 
 static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
 {
-	u16 auth_type = wps->wps->auth_types;
-
-	/* Select the best authentication type */
-	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;
-	else if (auth_type & WPS_AUTH_SHARED)
-		auth_type = WPS_AUTH_SHARED;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)", auth_type);
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
+		   wps->wps->ap_auth_type);
 	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
 	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, auth_type);
+	wpabuf_put_be16(msg, wps->wps->ap_auth_type);
 	return 0;
 }
 
 
 static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
 {
-	u16 encr_type = wps->wps->encr_types;
-
-	/* Select the best encryption type */
-	if (wps->wps->auth_types & (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;
-	} else {
-		if (encr_type & WPS_ENCR_WEP)
-			encr_type = WPS_ENCR_WEP;
-		else if (encr_type & WPS_ENCR_NONE)
-			encr_type = WPS_ENCR_NONE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)", encr_type);
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
+		   wps->wps->ap_encr_type);
 	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
 	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, encr_type);
+	wpabuf_put_be16(msg, wps->wps->ap_encr_type);
 	return 0;
 }
 
 
 static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
 {
-	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%u)",
+		   (unsigned int) wps->wps->network_key_len);
 	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
 	wpabuf_put_be16(msg, wps->wps->network_key_len);
 	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
@@ -310,6 +286,9 @@
 
 static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
 {
+	const u8 *start, *end;
+	int ret;
+
 	if (wps->wps->ap_settings) {
 		wpa_printf(MSG_DEBUG, "WPS:  * AP Settings (pre-configured)");
 		wpabuf_put_data(plain, wps->wps->ap_settings,
@@ -317,11 +296,19 @@
 		return 0;
 	}
 
-	return wps_build_cred_ssid(wps, plain) ||
+	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings based on current configuration");
+	start = wpabuf_put(plain, 0);
+	ret = wps_build_cred_ssid(wps, plain) ||
 		wps_build_cred_mac_addr(wps, plain) ||
 		wps_build_cred_auth_type(wps, plain) ||
 		wps_build_cred_encr_type(wps, plain) ||
 		wps_build_cred_network_key(wps, plain);
+	end = wpabuf_put(plain, 0);
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings",
+			start, end - start);
+
+	return ret;
 }
 
 
@@ -514,6 +501,24 @@
 		return -1;
 	}
 
+	if (wps->peer_pubkey_hash_set) {
+		u8 hash[WPS_HASH_LEN];
+		sha256_vector(1, &pk, &pk_len, hash);
+		if (os_memcmp(hash, wps->peer_pubkey_hash,
+			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+			wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
+			wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
+				    pk, pk_len);
+			wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
+				    "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
+			wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
+				    wps->peer_pubkey_hash,
+				    WPS_OOB_PUBKEY_HASH_LEN);
+			wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
+			return -1;
+		}
+	}
+
 	wpabuf_free(wps->dh_pubkey_r);
 	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
 	if (wps->dh_pubkey_r == NULL)
@@ -864,6 +869,12 @@
 	wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
 		   "ID from %u to %u", wps->dev_pw_id, id);
 
+	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Workaround - ignore PBC-to-PIN change");
+		return 0;
+	}
+
 	if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
 		wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
 		os_free(wps->dev_password);
@@ -923,6 +934,38 @@
 		return WPS_CONTINUE;
 	}
 
+#ifdef CONFIG_WPS_NFC
+	if (wps->peer_pubkey_hash_set) {
+		struct wpabuf *decrypted;
+		struct wps_parse_attr eattr;
+
+		decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+						      attr->encr_settings_len);
+		if (decrypted == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt "
+				   "Encrypted Settings attribute");
+			wps->state = SEND_WSC_NACK;
+			return WPS_CONTINUE;
+		}
+
+		wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted "
+			   "Settings attribute");
+		if (wps_parse_msg(decrypted, &eattr) < 0 ||
+		    wps_process_key_wrap_auth(wps, decrypted,
+					      eattr.key_wrap_auth) ||
+		    wps_process_creds(wps, eattr.cred, eattr.cred_len,
+				      eattr.num_cred, attr->version2 != NULL)) {
+			wpabuf_free(decrypted);
+			wps->state = SEND_WSC_NACK;
+			return WPS_CONTINUE;
+		}
+		wpabuf_free(decrypted);
+
+		wps->state = WPS_MSG_DONE;
+		return WPS_CONTINUE;
+	}
+#endif /* CONFIG_WPS_NFC */
+
 	wps->state = SEND_M3;
 	return WPS_CONTINUE;
 }
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 5694997..8e9ee7a 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -185,10 +185,8 @@
 	dl_list_del(&ap->list);
 	wps_er_ap_free(ap);
 
-	if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
-		eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
+	if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
 		wps_er_deinit_finish(er, NULL);
-	}
 }
 
 
@@ -1347,9 +1345,19 @@
 	struct wps_er *er = eloop_data;
 	void (*deinit_done_cb)(void *ctx);
 	void *deinit_done_ctx;
+	struct wps_er_ap *ap, *tmp;
 
 	wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
 
+	dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
+			      list) {
+		wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
+			   inet_ntoa(ap->addr), ap->location);
+		dl_list_del(&ap->list);
+		wps_er_ap_free(ap);
+	}
+
+	eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
 	deinit_done_cb = er->deinit_done_cb;
 	deinit_done_ctx = er->deinit_done_ctx;
 	os_free(er->ip_addr_text);
@@ -2032,8 +2040,7 @@
 	os_memset(&data, 0, sizeof(data));
 	data.wps = wps;
 	data.use_cred = cred;
-	if (wps_build_version(ret) ||
-	    wps_build_cred(&data, ret) ||
+	if (wps_build_cred(&data, ret) ||
 	    wps_build_wfa_ext(ret, 0, NULL, 0)) {
 		wpabuf_free(ret);
 		return NULL;
@@ -2063,4 +2070,29 @@
 	return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
 }
 
+
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+					struct wps_context *wps, const u8 *uuid,
+					const u8 *addr, struct wpabuf *pubkey)
+{
+	struct wps_er_ap *ap;
+
+	if (er == NULL)
+		return NULL;
+
+	ap = wps_er_ap_get(er, NULL, uuid, addr);
+	if (ap == NULL)
+		return NULL;
+	if (ap->ap_settings == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+			   "selected AP");
+		return NULL;
+	}
+
+	os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
+	wps->ssid_len = ap->ap_settings->ssid_len;
+
+	return wps_build_nfc_handover_sel(wps, pubkey, addr, 0);
+}
+
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index dac1250..22070db 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -75,6 +75,9 @@
 	size_t alt_dev_password_len;
 	u16 alt_dev_pw_id;
 
+	u8 peer_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+	int peer_pubkey_hash_set;
+
 	/**
 	 * request_type - Request Type attribute from (Re)AssocReq
 	 */
@@ -173,6 +176,8 @@
 			 size_t dev_pw_len);
 struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
 int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr);
+int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands);
+int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel);
 
 /* wps_attr_process.c */
 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
diff --git a/src/wps/wps_module_tests.c b/src/wps/wps_module_tests.c
new file mode 100644
index 0000000..6800e86
--- /dev/null
+++ b/src/wps/wps_module_tests.c
@@ -0,0 +1,337 @@
+/*
+ * WPS module tests
+ * Copyright (c) 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 "wps_attr_parse.h"
+
+struct wps_attr_parse_test {
+	const char *data;
+	int result;
+	int extra;
+};
+
+struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
+	/* Empty message */
+	{ "", 0, 0 },
+	/* Truncated attribute header */
+	{ "10", -1, 0 },
+	{ "1010", -1, 0 },
+	{ "101000", -1, 0 },
+	/* Attribute overflow */
+	{ "10100001", -1, 0 },
+#ifdef CONFIG_WPS_STRICT
+	{ "10270000001057000101", -1, 0 },
+	{ "1027000010570001010000000000", -1, 0 },
+#else /* CONFIG_WPS_STRICT */
+	/* Network Key workaround */
+	{ "10270000001057000101", 0, 1 },
+	{ "10230000001057000101", -1, 0 },
+	{ "10270000101057000101", -1, 0 },
+	/* Mac OS X 10.6 padding workaround */
+	{ "1027000010570001010000000000", 0, 1 },
+	{ "1027000010570001010000000000000001000000", -1, 0 },
+#endif /* CONFIG_WPS_STRICT */
+	/* Version */
+	{ "104a000110", 0, 0 },
+	{ "104a0000", -1, 0 },
+	/* Message Type */
+	{ "1022000101", 0, 0 },
+	{ "10220000", -1, 0 },
+	/* Enrollee Nonce */
+	{ "101a001000112233445566778899aabbccddeeff", 0, 0 },
+	{ "101a00111122334455667788990011223344556677", -1, 0 },
+	/* Registrar Nonce */
+	{ "1039001000112233445566778899aabbccddeeff", 0, 0 },
+	{ "103900111122334455667788990011223344556677", -1, 0 },
+	/* UUID-E */
+	{ "1047001000112233445566778899aabbccddeeff", 0, 0 },
+	{ "10470000", -1, 0 },
+	{ "104700111122334455667788990011223344556677", -1, 0 },
+	/* UUID-R */
+	{ "1048001000112233445566778899aabbccddeeff", 0, 0 },
+	{ "10480000", -1, 0 },
+	{ "104800111122334455667788990011223344556677", -1, 0 },
+	/* Auth Type Flags */
+	{ "100400021122", 0, 0 },
+	{ "10040001ff", -1, 0 },
+	/* Encr Type Flags */
+	{ "101000021122", 0, 0 },
+	{ "10100001ff", -1, 0 },
+	/* Connection Type Flags */
+	{ "100d0001ff", 0, 0 },
+	{ "100d0002ffff", -1, 0 },
+	/* Config Methods */
+	{ "10080002ffff", 0, 0 },
+	{ "10080001ff", -1, 0 },
+	/* Selected Registrar Config Methods */
+	{ "10530002ffff", 0, 0 },
+	{ "10530001ff", -1, 0 },
+	/* Primary Device Type */
+	{ "105400081122334455667788", 0, 0 },
+	{ "105400111122334455667788990011223344556677", -1, 0 },
+	/* RF Bands */
+	{ "103c0001ff", 0, 0 },
+	{ "103c0002ffff", -1, 0 },
+	/* Association State */
+	{ "10020002ffff", 0, 0 },
+	{ "10020001ff", -1, 0 },
+	/* Config Error */
+	{ "100900020001", 0, 0 },
+	{ "10090001ff", -1, 0 },
+	/* Device Password ID */
+	{ "101200020004", 0, 0 },
+	{ "10120001ff", -1, 0 },
+	/* OOB Device Password */
+	{ "102c001611223344556677889900112233445566778899000007", 0, 0 },
+	{ "102c0036112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344", 0, 0 },
+	{ "102c0001ff", -1, 0 },
+	{ "102c003711223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455", -1, 0 },
+	{ "102c002511223344556677889900112233445566778899001122334455667788990011223344556677", -1, 0 },
+	/* OS Version */
+	{ "102d000411223344", 0, 0 },
+	{ "102d00111122334455667788990011223344556677", -1, 0 },
+	/* WPS State */
+	{ "1044000101", 0, 0 },
+	{ "10440002ffff", -1, 0 },
+	/* Authenticator */
+	{ "100500081122334455667788", 0, 0 },
+	{ "10050000", -1, 0 },
+	{ "100500111122334455667788990011223344556677", -1, 0 },
+	/* R-Hash1 */
+	{ "103d00201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+	{ "103d0000", -1, 0 },
+	{ "103d0021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+	/* R-Hash2 */
+	{ "103e00201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+	{ "103e0000", -1, 0 },
+	{ "103e0021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+	/* E-Hash1 */
+	{ "101400201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+	{ "10140000", -1, 0 },
+	{ "10140021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+	/* E-Hash2 */
+	{ "101500201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+	{ "10150000", -1, 0 },
+	{ "10150021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+	/* R-SNonce1 */
+	{ "103f001011223344556677889900112233445566", 0, 0 },
+	{ "103f0000", -1, 0 },
+	{ "103f00111122334455667788990011223344556677", -1, 0 },
+	/* R-SNonce2 */
+	{ "1040001011223344556677889900112233445566", 0, 0 },
+	{ "10400000", -1, 0 },
+	{ "104000111122334455667788990011223344556677", -1, 0 },
+	/* E-SNonce1 */
+	{ "1016001011223344556677889900112233445566", 0, 0 },
+	{ "10160000", -1, 0 },
+	{ "101600111122334455667788990011223344556677", -1, 0 },
+	/* E-SNonce2 */
+	{ "1017001011223344556677889900112233445566", 0, 0 },
+	{ "10170000", -1, 0 },
+	{ "101700111122334455667788990011223344556677", -1, 0 },
+	/* Key Wrap Authenticator */
+	{ "101e00081122334455667788", 0, 0 },
+	{ "101e0000", -1, 0 },
+	{ "101e0009112233445566778899", -1, 0 },
+	/* Authentication Type */
+	{ "100300020001", 0, 0 },
+	{ "10030001ff", -1, 0 },
+	/* Encryption Type */
+	{ "100f00020001", 0, 0 },
+	{ "100f0001ff", -1, 0 },
+	/* Network Index */
+	{ "1026000101", 0, 0 },
+	{ "10260002ffff", -1, 0 },
+	/* Network Key Index */
+	{ "1028000101", 0, 3 },
+	{ "10280002ffff", -1, 0 },
+	/* MAC Address */
+	{ "10200006112233445566", 0, 0 },
+	{ "10200000", -1, 0 },
+	{ "1020000711223344556677", -1, 0 },
+	/* Selected Registrar */
+	{ "1041000101", 0, 0 },
+	{ "10410002ffff", -1, 0 },
+	/* Request Type */
+	{ "103a000101", 0, 0 },
+	{ "103a0002ffff", -1, 0 },
+	/* Response Type */
+	{ "103b000101", 0, 0 },
+	{ "103b0002ffff", -1, 0 },
+	/* Manufacturer */
+	{ "10210000", 0, 0 },
+	/* Model Name */
+	{ "10230000", 0, 0 },
+	/* Model Number */
+	{ "10240000", 0, 0 },
+	/* Serial Number */
+	{ "10420000", 0, 0 },
+	/* Device Name */
+	{ "10110000", 0, 0 },
+	/* Public Key */
+	{ "10320000", 0, 0 },
+	/* Enc Settings */
+	{ "10180000", 0, 0 },
+	/* SSID */
+	{ "10450000", 0, 0 },
+	/* AP Setup Locked */
+	{ "1057000101", 0, 0 },
+	{ "10570002ffff", -1, 0 },
+	/* Requested Device Type */
+	{ "106a00081122334455667788", 0, 0 },
+	{ "106a0000", -1, 0 },
+	{ "106a0009112233445566778899", -1, 0 },
+	/* More than maximum Requested Device Type attributes */
+	{ "106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788", 0, 4 },
+	/* Secondary Device Type List */
+	{ "105500081122334455667788", 0, 0 },
+	{ "1055000711223344556677", -1, 0 },
+	{ "1055008811223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566", -1, 0 },
+	/* AP Channel */
+	{ "100100020001", 0, 0 },
+	{ "1001000101", -1, 0 },
+	/* Skip invalid Vendor Extension */
+	{ "10490000", 0, 0 },
+	{ "1049000100", 0, 0 },
+	{ "104900020000", 0, 0 },
+	/* Too long unknown vendor extension */
+	{ "10490401"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "112233445566778899001122334455667788990011223344556677889900"
+	  "1122334455", -1, 0 },
+	/* Maximum unknown vendor extensions */
+	{ "10490003111111104900032222221049000333333310490003444444104900035555551049000366666610490003777777104900038888881049000399999910490003AAAAAA", 0, 5 },
+	/* More than maximum unknown vendor extensions */
+	{ "10490003111111104900032222221049000333333310490003444444104900035555551049000366666610490003777777104900038888881049000399999910490003AAAAAA10490003BBBBBB", -1, 0 },
+	/* WFA vendor extensions */
+	{ "1049000300372a", 0, 0 },
+	{ "1049000400372a00", 0, 0 },
+	{ "1049000500372a0001", 0, 0 },
+	{ "1049001600372a0001ff0100020101030101040101ff00fe0101", 0, 6 },
+	/* Invalid Version2 length */
+	{ "1049000500372a0000", -1, 0 },
+	/* Invalid Network Key Shareable length */
+	{ "1049000500372a0200", -1, 0 },
+	/* Invalid Requedt To Enroll length */
+	{ "1049000500372a0300", -1, 0 },
+	/* Invalid Settings Delay Time length */
+	{ "1049000500372a0400", -1, 0 },
+	/* More than maximum Credential attributes */
+	{ "100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000", 0, 2 },
+};
+
+
+static int wps_attr_parse_tests(void)
+{
+	struct wps_parse_attr attr;
+	unsigned int i;
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "WPS attribute parsing tests");
+
+	for (i = 0; i < ARRAY_SIZE(wps_attr_parse_test_cases); i++) {
+		struct wpabuf *buf;
+		size_t len;
+		struct wps_attr_parse_test *test =
+			&wps_attr_parse_test_cases[i];
+
+		len = os_strlen(test->data) / 2;
+		buf = wpabuf_alloc(len);
+		if (buf == NULL)
+			return -1;
+		if (hexstr2bin(test->data, wpabuf_put(buf, len), len) < 0) {
+			wpabuf_free(buf);
+			return -1;
+		}
+		if (wps_parse_msg(buf, &attr) != test->result) {
+			wpa_printf(MSG_ERROR, "WPS attribute parsing test %u failed: %s",
+				   i, test->data);
+			ret = -1;
+		}
+		switch (test->extra) {
+		case 1:
+			if (!attr.network_key || !attr.ap_setup_locked)
+				ret = -1;
+			break;
+		case 2:
+			if (attr.num_cred != MAX_CRED_COUNT)
+				ret = -1;
+			break;
+		case 3:
+			if (!attr.network_key_idx)
+				ret = -1;
+			break;
+		case 4:
+			if (attr.num_req_dev_type != MAX_REQ_DEV_TYPE_COUNT)
+				ret = -1;
+			break;
+		case 5:
+			if (attr.num_vendor_ext != MAX_WPS_PARSE_VENDOR_EXT)
+				ret = -1;
+			break;
+		case 6:
+			if (!attr.version2 ||
+			    !attr.authorized_macs ||
+			    !attr.network_key_shareable ||
+			    !attr.request_to_enroll ||
+			    !attr.settings_delay_time)
+				ret = -1;
+			break;
+		}
+		wpabuf_free(buf);
+	}
+
+	return ret;
+}
+
+
+int wps_module_tests(void)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "WPS module tests");
+
+	if (wps_attr_parse_tests() < 0)
+		ret = -1;
+
+	return ret;
+}
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b7fcd9c..6d879be 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -31,9 +31,11 @@
 struct wps_nfc_pw_token {
 	struct dl_list list;
 	u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+	unsigned int peer_pk_hash_known:1;
 	u16 pw_id;
 	u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1];
 	size_t dev_pw_len;
+	int pk_hash_provided_oob; /* whether own PK hash was provided OOB */
 };
 
 
@@ -82,7 +84,7 @@
 #define PIN_LOCKED BIT(0)
 #define PIN_EXPIRES BIT(1)
 	int flags;
-	struct os_time expiration;
+	struct os_reltime expiration;
 	u8 enrollee_addr[ETH_ALEN];
 };
 
@@ -113,7 +115,7 @@
 	struct wps_pbc_session *next;
 	u8 addr[ETH_ALEN];
 	u8 uuid_e[WPS_UUID_LEN];
-	struct os_time timestamp;
+	struct os_reltime timestamp;
 };
 
 
@@ -183,7 +185,9 @@
 	u8 p2p_dev_addr[ETH_ALEN];
 
 	u8 pbc_ignore_uuid[WPS_UUID_LEN];
-	struct os_time pbc_ignore_start;
+#ifdef WPS_WORKAROUNDS
+	struct os_reltime pbc_ignore_start;
+#endif /* WPS_WORKAROUNDS */
 };
 
 
@@ -311,9 +315,9 @@
 					  const u8 *addr, const u8 *uuid_e)
 {
 	struct wps_pbc_session *pbc, *prev = NULL;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	pbc = reg->pbc_sessions;
 	while (pbc) {
@@ -347,7 +351,8 @@
 	pbc = pbc->next;
 
 	while (pbc) {
-		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+		if (os_reltime_expired(&now, &pbc->timestamp,
+				       WPS_PBC_WALK_TIME)) {
 			prev->next = NULL;
 			wps_free_pbc_sessions(pbc);
 			break;
@@ -367,13 +372,8 @@
 	pbc = reg->pbc_sessions;
 	while (pbc) {
 		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
-#ifdef ANDROID_P2P
-		    (p2p_dev_addr && !is_zero_ether_addr(pbc->addr) &&
-		     os_memcmp(pbc->addr, p2p_dev_addr, ETH_ALEN) ==
-#else
 		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
 		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
-#endif
 		     0)) {
 			if (prev)
 				prev->next = pbc->next;
@@ -400,9 +400,9 @@
 	int count = 0;
 	struct wps_pbc_session *pbc;
 	struct wps_pbc_session *first = NULL;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
 
@@ -418,9 +418,9 @@
 			   MAC2STR(pbc->addr));
 		wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
 			    pbc->uuid_e, WPS_UUID_LEN);
-		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
-			wpa_printf(MSG_DEBUG, "WPS: PBC walk time has "
-				   "expired");
+		if (os_reltime_expired(&now, &pbc->timestamp,
+				       WPS_PBC_WALK_TIME)) {
+			wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired");
 			break;
 		}
 		if (first &&
@@ -753,7 +753,7 @@
 
 	if (timeout) {
 		p->flags |= PIN_EXPIRES;
-		os_get_time(&p->expiration);
+		os_get_reltime(&p->expiration);
 		p->expiration.sec += timeout;
 	}
 
@@ -802,13 +802,13 @@
 static void wps_registrar_expire_pins(struct wps_registrar *reg)
 {
 	struct wps_uuid_pin *pin, *prev;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
 	{
 		if ((pin->flags & PIN_EXPIRES) &&
-		    os_time_before(&pin->expiration, &now)) {
+		    os_reltime_before(&pin->expiration, &now)) {
 			wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
 				    pin->uuid, WPS_UUID_LEN);
 			wps_registrar_remove_pin(reg, pin);
@@ -1042,7 +1042,9 @@
 		wps_registrar_remove_pbc_session(registrar,
 						 uuid_e, NULL);
 		wps_registrar_pbc_completed(registrar);
-		os_get_time(&registrar->pbc_ignore_start);
+#ifdef WPS_WORKAROUNDS
+		os_get_reltime(&registrar->pbc_ignore_start);
+#endif /* WPS_WORKAROUNDS */
 		os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
 	} else {
 		wps_registrar_pin_completed(registrar);
@@ -1145,9 +1147,9 @@
 #ifdef WPS_WORKAROUNDS
 	if (reg->pbc_ignore_start.sec &&
 	    os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
-		struct os_time now, dur;
-		os_get_time(&now);
-		os_time_sub(&now, &reg->pbc_ignore_start, &dur);
+		struct os_reltime now, dur;
+		os_get_reltime(&now);
+		os_reltime_sub(&now, &reg->pbc_ignore_start, &dur);
 		if (dur.sec >= 0 && dur.sec < 5) {
 			wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
 				   "based on Probe Request from the Enrollee "
@@ -1360,10 +1362,23 @@
 		pin_len = 8;
 #ifdef CONFIG_WPS_NFC
 	} else if (wps->nfc_pw_token) {
+		if (wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+		{
+			wpa_printf(MSG_DEBUG, "WPS: Using NFC connection "
+				   "handover and abbreviated WPS handshake "
+				   "without Device Password");
+			return 0;
+		}
 		wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
 			   "Password Token");
 		pin = wps->nfc_pw_token->dev_pw;
 		pin_len = wps->nfc_pw_token->dev_pw_len;
+	} else if (wps->dev_pw_id >= 0x10 &&
+		   wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
+		   wps->wps->ap_nfc_dev_pw) {
+		wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from own NFC Password Token");
+		pin = wpabuf_head(wps->wps->ap_nfc_dev_pw);
+		pin_len = wpabuf_len(wps->wps->ap_nfc_dev_pw);
 #endif /* CONFIG_WPS_NFC */
 	} else {
 		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
@@ -1379,7 +1394,8 @@
 	}
 	if (pin == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
-			   "the Enrollee");
+			   "the Enrollee (context %p registrar %p)",
+			   wps->wps, wps->wps->registrar);
 		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
 				  &wps->peer_dev);
 		return -1;
@@ -1776,6 +1792,7 @@
 static struct wpabuf * wps_build_m2(struct wps_data *wps)
 {
 	struct wpabuf *msg;
+	int config_in_m2 = 0;
 
 	if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
 		return NULL;
@@ -1806,14 +1823,41 @@
 	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
 	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
 	    wps_build_os_version(&wps->wps->dev, msg) ||
-	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
-	    wps_build_authenticator(wps, msg)) {
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+#ifdef CONFIG_WPS_NFC
+	if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob &&
+	    wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
+		/*
+		 * Use abbreviated handshake since public key hash allowed
+		 * Enrollee to validate our public key similarly to how Enrollee
+		 * public key was validated. There is no need to validate Device
+		 * Password in this case.
+		 */
+		struct wpabuf *plain = wpabuf_alloc(500);
+		if (plain == NULL ||
+		    wps_build_cred(wps, plain) ||
+		    wps_build_key_wrap_auth(wps, plain) ||
+		    wps_build_encr_settings(wps, msg, plain)) {
+			wpabuf_free(msg);
+			wpabuf_free(plain);
+			return NULL;
+		}
+		wpabuf_free(plain);
+		config_in_m2 = 1;
+	}
+#endif /* CONFIG_WPS_NFC */
+
+	if (wps_build_authenticator(wps, msg)) {
 		wpabuf_free(msg);
 		return NULL;
 	}
 
 	wps->int_reg = 1;
-	wps->state = RECV_M3;
+	wps->state = config_in_m2 ? RECV_DONE : RECV_M3;
 	return msg;
 }
 
@@ -2527,6 +2571,9 @@
 	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
+#ifdef CONFIG_WPS_NFC
+	    wps->dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
+#endif /* CONFIG_WPS_NFC */
 	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
 	     !wps->wps->registrar->pbc)) {
 		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
@@ -2536,14 +2583,17 @@
 	}
 
 #ifdef CONFIG_WPS_NFC
-	if (wps->dev_pw_id >= 0x10) {
+	if (wps->dev_pw_id >= 0x10 ||
+	    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
 		struct wps_nfc_pw_token *token;
 		const u8 *addr[1];
 		u8 hash[WPS_HASH_LEN];
 
+		wpa_printf(MSG_DEBUG, "WPS: Searching for NFC token match for id=%d (ctx %p registrar %p)",
+			   wps->dev_pw_id, wps->wps, wps->wps->registrar);
 		token = wps_get_nfc_pw_token(
 			&wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
-		if (token) {
+		if (token && token->peer_pk_hash_known) {
 			wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
 				   "Password Token");
 			dl_list_del(&token->list);
@@ -2555,8 +2605,19 @@
 				      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
 				wpa_printf(MSG_ERROR, "WPS: Public Key hash "
 					   "mismatch");
-				return WPS_FAILURE;
+				wps->state = SEND_M2D;
+				wps->config_error =
+					WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
+				return WPS_CONTINUE;
 			}
+		} else if (token) {
+			wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+				   "Password Token (no peer PK hash)");
+			wps->nfc_pw_token = token;
+		} else if (wps->dev_pw_id >= 0x10 &&
+			   wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
+			   wps->wps->ap_nfc_dev_pw) {
+			wpa_printf(MSG_DEBUG, "WPS: Found match with own NFC Password Token");
 		}
 	}
 #endif /* CONFIG_WPS_NFC */
@@ -3191,7 +3252,9 @@
 						 wps->uuid_e,
 						 wps->p2p_dev_addr);
 		wps_registrar_pbc_completed(wps->wps->registrar);
-		os_get_time(&wps->wps->registrar->pbc_ignore_start);
+#ifdef WPS_WORKAROUNDS
+		os_get_reltime(&wps->wps->registrar->pbc_ignore_start);
+#endif /* WPS_WORKAROUNDS */
 		os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
 			  WPS_UUID_LEN);
 	} else {
@@ -3448,7 +3511,7 @@
 			    struct wps_credential *cred)
 {
 #ifdef CONFIG_WPS2
-	printf("encr_type=0x%x\n", cred->encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type);
 	if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
 				 WPS_ENCR_AES))) {
 		if (cred->encr_type & WPS_ENCR_WEP) {
@@ -3488,25 +3551,39 @@
 
 int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
 				   const u8 *pubkey_hash, u16 pw_id,
-				   const u8 *dev_pw, size_t dev_pw_len)
+				   const u8 *dev_pw, size_t dev_pw_len,
+				   int pk_hash_provided_oob)
 {
 	struct wps_nfc_pw_token *token;
 
 	if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
 		return -1;
 
+	if (pw_id == DEV_PW_NFC_CONNECTION_HANDOVER &&
+	    (pubkey_hash == NULL || !pk_hash_provided_oob)) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected NFC Password Token "
+			   "addition - missing public key hash");
+		return -1;
+	}
+
 	wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, pw_id);
 
 	token = os_zalloc(sizeof(*token));
 	if (token == NULL)
 		return -1;
 
-	os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+	token->peer_pk_hash_known = pubkey_hash != NULL;
+	if (pubkey_hash)
+		os_memcpy(token->pubkey_hash, pubkey_hash,
+			  WPS_OOB_PUBKEY_HASH_LEN);
 	token->pw_id = pw_id;
-	wpa_snprintf_hex_uppercase((char *) token->dev_pw,
-				   sizeof(token->dev_pw),
-				   dev_pw, dev_pw_len);
-	token->dev_pw_len = dev_pw_len * 2;
+	token->pk_hash_provided_oob = pk_hash_provided_oob;
+	if (dev_pw) {
+		wpa_snprintf_hex_uppercase((char *) token->dev_pw,
+					   sizeof(token->dev_pw),
+					   dev_pw, dev_pw_len);
+		token->dev_pw_len = dev_pw_len * 2;
+	}
 
 	dl_list_add(&reg->nfc_pw_tokens, &token->list);
 
@@ -3535,8 +3612,7 @@
 	u16 id;
 	size_t dev_pw_len;
 
-	if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
-	    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+	if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
 	    oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
 	    WPS_OOB_DEVICE_PASSWORD_LEN)
 		return -1;
@@ -3555,7 +3631,7 @@
 	wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
 
 	return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
-					      dev_pw_len);
+					      dev_pw_len, 0);
 }
 
 
@@ -3565,6 +3641,14 @@
 	wps_registrar_remove_authorized_mac(reg,
 					    (u8 *) "\xff\xff\xff\xff\xff\xff");
 	wps_registrar_selected_registrar_changed(reg, 0);
+
+	/*
+	 * Free the NFC password token if it was used only for a single protocol
+	 * run. The static handover case uses the same password token multiple
+	 * times, so do not free that case here.
+	 */
+	if (token->peer_pk_hash_known)
+		os_free(token);
 }
 
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index bea2b33..6fb3d4c 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -432,23 +432,6 @@
 }
 
 
-int send_wpabuf(int fd, struct wpabuf *buf)
-{
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
-		   (unsigned long) wpabuf_len(buf));
-	errno = 0;
-	if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
-	    (int) wpabuf_len(buf)) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
-			   "errno=%d (%s)",
-			   errno, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static void wpabuf_put_property(struct wpabuf *buf, const char *name,
 				const char *value)
 {
@@ -480,14 +463,14 @@
 		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
 		"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
 	const char *format_tail = "</e:propertyset>\n";
-	struct os_time now;
+	struct os_reltime now;
 
 	if (dl_list_empty(&sm->subscriptions)) {
 		/* optimize */
 		return;
 	}
 
-	if (os_get_time(&now) == 0) {
+	if (os_get_reltime(&now) == 0) {
 		if (now.sec != sm->last_event_sec) {
 			sm->last_event_sec = now.sec;
 			sm->num_events_in_sec = 1;
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index 5c39f7e..f289fe6 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -158,7 +158,6 @@
 struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
 					const u8 uuid[UUID_LEN]);
 void subscr_addr_delete(struct subscr_addr *a);
-int send_wpabuf(int fd, struct wpabuf *buf);
 int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
 		   u8 mac[ETH_ALEN]);
 
diff --git a/src/wps/wps_validate.c b/src/wps/wps_validate.c
index e366256..1c6a14b 100644
--- a/src/wps/wps_validate.c
+++ b/src/wps/wps_validate.c
@@ -267,7 +267,7 @@
 		return 0;
 	}
 	val = WPA_GET_BE16(config_error);
-	if (val > 18) {
+	if (val > 20) {
 		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error "
 			   "attribute value 0x%04x", val);
 		return -1;
@@ -290,7 +290,7 @@
 		return 0;
 	}
 	val = WPA_GET_BE16(dev_password_id);
-	if (val >= 0x0006 && val <= 0x000f) {
+	if (val >= 0x0008 && val <= 0x000f) {
 		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID "
 			   "attribute value 0x%04x", val);
 		return -1;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index bef01b7..2880b2d 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -51,9 +51,6 @@
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/common
@@ -71,9 +68,13 @@
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += $(LOCAL_PATH)/src/wps
 INCLUDES += external/openssl/include
-INCLUDES += system/security/keystore
+INCLUDES += system/security/keystore/include
 ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
 INCLUDES += external/libnl/include
+else
+INCLUDES += external/libnl-headers
+endif
 endif
 
 ifdef CONFIG_FIPS
@@ -258,6 +259,7 @@
 OBJS += src/p2p/p2p_dev_disc.c
 OBJS += src/p2p/p2p_group.c
 OBJS += src/ap/p2p_hostapd.c
+OBJS += src/utils/bitfield.c
 L_CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
@@ -507,7 +509,7 @@
 ifdef CONFIG_EAP_PROXY
 L_CFLAGS += -DCONFIG_EAP_PROXY
 OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
-include eap_proxy_$(CONFIG_EAP_PROXY).mk
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
 CONFIG_IEEE8021X_EAPOL=y
 endif
 
@@ -772,6 +774,9 @@
 OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
 endif
 ifdef CONFIG_WNM
 OBJS += src/ap/wnm_ap.c
@@ -787,6 +792,9 @@
 
 ifdef CONFIG_IEEE80211N
 L_CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
 endif
 
 ifdef NEED_AP_MLME
@@ -794,6 +802,7 @@
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
 OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
@@ -1122,7 +1131,7 @@
 ifdef NEED_AES_OMAC1
 NEED_AES_ENC=y
 ifdef CONFIG_OPENSSL_CMAC
-CFLAGS += -DCONFIG_OPENSSL_CMAC
+L_CFLAGS += -DCONFIG_OPENSSL_CMAC
 else
 AESOBJS += src/crypto/aes-omac1.c
 endif
@@ -1171,7 +1180,10 @@
 endif
 endif
 
-MD5OBJS = src/crypto/md5.c
+MD5OBJS =
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += src/crypto/md5-internal.c
@@ -1425,7 +1437,7 @@
 endif
 
 ifdef CONFIG_AUTOSCAN_PERIODIC
-CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
 OBJS += autoscan_periodic.c
 NEED_AUTOSCAN=y
 endif
@@ -1552,11 +1564,19 @@
 LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
 endif
 LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifdef CONFIG_EAP_PROXY
+LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY)
+LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
+endif
 ifeq ($(CONFIG_TLS), openssl)
 LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
 endif
 ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
 LOCAL_SHARED_LIBRARIES += libnl
+else
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
 endif
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_SRC_FILES := $(OBJS)
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 3f10e11..e40cf91 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,8 +1,113 @@
 ChangeLog for wpa_supplicant
 
-????-??-?? - v2.1
-	* added support for simulataneous authentication of equals (SAE) for
+2014-02-04 - v2.1
+	* added support for simultaneous authentication of equals (SAE) for
 	  stronger password-based authentication with WPA2-Personal
+	* improved P2P negotiation and group formation robustness
+	  - avoid unnecessary Dialog Token value changes during retries
+	  - avoid more concurrent scanning cases during full group formation
+	    sequence
+	  - do not use potentially obsolete scan result data from driver
+	    cache for peer discovery/updates
+	  - avoid undesired re-starting of GO negotiation based on Probe
+	    Request frames
+	  - increase GO Negotiation and Invitation timeouts to address busy
+	    environments and peers that take long time to react to messages,
+	    e.g., due to power saving
+	  - P2P Device interface type
+	* improved P2P channel selection (use more peer information and allow
+	  more local options)
+	* added support for optional per-device PSK assignment by P2P GO
+	  (wpa_cli p2p_set per_sta_psk <0/1>)
+	* added P2P_REMOVE_CLIENT for removing a client from P2P groups
+	  (including persistent groups); this can be used to securely remove
+	  a client from a group if per-device PSKs are used
+	* added more configuration flexibility for allowed P2P GO/client
+	  channels (p2p_no_go_freq list and p2p_add_cli_chan=0/1)
+	* added nl80211 functionality
+	  - VHT configuration for nl80211
+	  - MFP (IEEE 802.11w) information for nl80211 command API
+	  - support split wiphy dump
+	  - FT (IEEE 802.11r) with driver-based SME
+	  - use advertised number of supported concurrent channels
+	  - QoS Mapping configuration
+	* improved TDLS negotiation robustness
+	* added more TDLS peer parameters to be configured to the driver
+	* optimized connection time by allowing recently received scan results
+	  to be used instead of having to run through a new scan
+	* fixed ctrl_iface BSS command iteration with RANGE argument and no
+	  exact matches; also fixed argument parsing for some cases with
+	  multiple arguments
+	* added 'SCAN TYPE=ONLY' ctrl_iface command to request manual scan
+	  without executing roaming/network re-selection on scan results
+	* added Session-Id derivation for EAP peer methods
+	* added fully automated regression testing with mac80211_hwsim
+	* changed configuration parser to reject invalid integer values
+	* allow AP/Enrollee to be specified with BSSID instead of UUID for
+	  WPS ER operations
+	* disable network block temporarily on repeated connection failures
+	* changed the default driver interface from wext to nl80211 if both are
+	  included in the build
+	* remove duplicate networks if WPS provisioning is run multiple times
+	* remove duplicate networks when Interworking network selection uses the
+	  same network
+	* added global freq_list configuration to allow scan frequencies to be
+	  limited for all cases instead of just for a specific network block
+	* added support for BSS Transition Management
+	* added option to use "IFNAME=<ifname> " prefix to use the global
+	  control interface connection to perform per-interface commands;
+	  similarly, allow global control interface to be used as a monitor
+	  interface to receive events from all interfaces
+	* fixed OKC-based PMKSA cache entry clearing
+	* fixed TKIP group key configuration with FT
+	* added support for using OCSP stapling to validate server certificate
+	  (ocsp=1 as optional and ocsp=2 as mandatory)
+	* added EAP-EKE peer
+	* added peer restart detection for IBSS RSN
+	* added domain_suffix_match (and domain_suffix_match2 for Phase 2
+	  EAP-TLS) to specify additional constraint for the server certificate
+	  domain name
+	* added support for external SIM/USIM processing in EAP-SIM, EAP-AKA,
+	  and EAP-AKA' (CTRL-REQ-SIM and CTRL-RSP-SIM commands over control
+	  interface)
+	* added global bgscan configuration option as a default for all network
+	  blocks that do not specify their own bgscan parameters
+	* added D-Bus methods for TDLS
+	* added more control to scan requests
+	  - "SCAN freq=<freq list>" can be used to specify which channels are
+	    scanned (comma-separated frequency ranges in MHz)
+	  - "SCAN passive=1" can be used to request a passive scan (no Probe
+	    Request frames are sent)
+	  - "SCAN use_id" can be used to request a scan id to be returned and
+	    included in event messages related to this specific scan operation
+	  - "SCAN only_new=1" can be used to request the driver/cfg80211 to
+	    report only BSS entries that have been updated during this scan
+	    round
+	  - these optional arguments to the SCAN command can be combined with
+	    each other
+	* modified behavior on externally triggered scans
+	  - avoid concurrent operations requiring full control of the radio when
+	    an externally triggered scan is detected
+	  - do not use results for internal roaming decision
+	* added a new cred block parameter 'temporary' to allow credential
+	  blocks to be stored separately even if wpa_supplicant configuration
+	  file is used to maintain other network information
+	* added "radio work" framework to schedule exclusive radio operations
+	  for off-channel functionality
+	  - reduce issues with concurrent operations that try to control which
+	    channel is used
+	  - allow external programs to request exclusive radio control in a way
+	    that avoids conflicts with wpa_supplicant
+	* added support for using Protected Dual of Public Action frames for
+	  GAS/ANQP exchanges when associated with PMF
+	* added support for WPS+NFC updates and P2P+NFC
+	  - improved protocol for WPS
+	  - P2P group formation/join based on NFC connection handover
+	  - new IPv4 address assignment for P2P groups (ip_addr_* configuration
+	    parameters on the GO) to replace DHCP
+	  - option to fetch and report alternative carrier records for external
+	    NFC operations
+	* various bug fixes
 
 2013-01-12 - v2.0
 	* removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 5698619..7b556e8 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -10,11 +10,17 @@
 export BINDIR ?= /usr/local/sbin/
 PKG_CONFIG ?= pkg-config
 
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
 
 -include .config
 
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+CONFIG_TDLS_TESTING=y
+endif
+
 BINALL=wpa_supplicant wpa_cli
 
 ifndef CONFIG_NO_WPA_PASSPHRASE
@@ -91,6 +97,14 @@
 OBJS_p += ../src/utils/os_$(CONFIG_OS).o
 OBJS_c += ../src/utils/os_$(CONFIG_OS).o
 
+ifdef CONFIG_MODULE_TESTS
+CFLAGS += -DCONFIG_MODULE_TESTS
+OBJS += wpas_module_tests.o
+ifdef CONFIG_WPS
+OBJS += ../src/wps/wps_module_tests.o
+endif
+endif
+
 ifdef CONFIG_WPA_TRACE
 CFLAGS += -DWPA_TRACE
 OBJS += ../src/utils/trace.o
@@ -100,10 +114,10 @@
 LDFLAGS += -rdynamic
 CFLAGS += -funwind-tables
 ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DWPA_TRACE_BFD
-LIBS += -lbfd
-LIBS_p += -lbfd
-LIBS_c += -lbfd
+CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD
+LIBS += -lbfd -ldl -liberty -lz
+LIBS_p += -lbfd -ldl -liberty -lz
+LIBS_c += -lbfd -ldl -liberty -lz
 endif
 endif
 
@@ -113,6 +127,13 @@
 OBJS += ../src/utils/$(CONFIG_ELOOP).o
 OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_p += -lrt
+endif
+
 ifdef CONFIG_ELOOP_POLL
 CFLAGS += -DCONFIG_ELOOP_POLL
 endif
@@ -122,6 +143,13 @@
 CFLAGS += -Werror -DEAPOL_TEST
 endif
 
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_p += -lgcov
+endif
+
 ifdef CONFIG_HT_OVERRIDES
 CFLAGS += -DCONFIG_HT_OVERRIDES
 endif
@@ -237,6 +265,7 @@
 OBJS += ../src/p2p/p2p_dev_disc.o
 OBJS += ../src/p2p/p2p_group.o
 OBJS += ../src/ap/p2p_hostapd.o
+OBJS += ../src/utils/bitfield.o
 CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
@@ -750,6 +779,9 @@
 OBJS += ../src/ap/eap_user_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
 endif
 ifdef CONFIG_WNM
 OBJS += ../src/ap/wnm_ap.o
@@ -765,6 +797,9 @@
 
 ifdef CONFIG_IEEE80211N
 CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
 endif
 
 ifdef NEED_AP_MLME
@@ -772,6 +807,7 @@
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
 OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
 ifdef CONFIG_WPS
@@ -1601,9 +1637,15 @@
 	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
 		-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
 
+ifdef CONFIG_CODE_COVERAGE
+%.o: %.c
+	@$(E) "  CC " $<
+	$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
+else
 %.o: %.c
 	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
 	@$(E) "  CC " $<
+endif
 
 %.service: %.service.in
 	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@@ -1655,11 +1697,18 @@
 fips:
 	$(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
 
+lcov-html: wpa_supplicant.gcda
+	lcov -c -d .. > lcov.info
+	genhtml lcov.info --output-directory lcov-html
+
 clean:
 	$(MAKE) -C ../src clean
 	$(MAKE) -C dbus clean
-	rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+	rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
 	rm -f wpa_priv
 	rm -f nfc_pw_token
+	rm -f lcov.info
+	rm -rf lcov-html
 
 -include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 78df89e..7f88cd6 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
@@ -949,3 +949,105 @@
 wpa_priv can control multiple interface with one process, but it is
 also possible to run multiple wpa_priv processes at the same time, if
 desired.
+
+
+Linux capabilities instead of privileged process
+------------------------------------------------
+
+wpa_supplicant performs operations that need special permissions, e.g.,
+to control the network connection. Traditionally this has been achieved
+by running wpa_supplicant as a privileged process with effective user id
+0 (root). Linux capabilities can be used to provide restricted set of
+capabilities to match the functions needed by wpa_supplicant. The
+minimum set of capabilities needed for the operations is CAP_NET_ADMIN
+and CAP_NET_RAW.
+
+setcap(8) can be used to set file capabilities. For example:
+
+sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant
+
+Please note that this would give anyone being able to run that
+wpa_supplicant binary access to the additional capabilities. This can
+further be limited by file owner/group and mode bits. For example:
+
+sudo chown wpas wpa_supplicant
+sudo chmod 0100 wpa_supplicant
+
+This combination of setcap, chown, and chmod commands would allow wpas
+user to execute wpa_supplicant with additional network admin/raw
+capabilities.
+
+Common way style of creating a control interface socket in
+/var/run/wpa_supplicant could not be done by this user, but this
+directory could be created before starting the wpa_supplicant and set to
+suitable mode to allow wpa_supplicant to create sockets
+there. Alternatively, other directory or abstract socket namespace could
+be used for the control interface.
+
+
+External requests for radio control
+-----------------------------------
+
+External programs can request wpa_supplicant to not start offchannel
+operations during other tasks that may need exclusive control of the
+radio. The RADIO_WORK control interface command can be used for this.
+
+"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be
+used to reserve a slot for radio access. If freq is specified, other
+radio work items on the same channel may be completed in
+parallel. Otherwise, all other radio work items are blocked during
+execution. Timeout is set to 10 seconds by default to avoid blocking
+wpa_supplicant operations for excessive time. If a longer (or shorter)
+safety timeout is needed, that can be specified with the optional
+timeout parameter. This command returns an identifier for the radio work
+item.
+
+Once the radio work item has been started, "EXT-RADIO-WORK-START <id>"
+event message is indicated that the external processing can start. Once
+the operation has been completed, "RADIO_WORK done <id>" is used to
+indicate that to wpa_supplicant. This allows other radio works to be
+performed. If this command is forgotten (e.g., due to the external
+program terminating), wpa_supplicant will time out the radio owrk item
+and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has
+happened. "RADIO_WORK done <id>" can also be used to cancel items that
+have not yet been started.
+
+For example, in wpa_cli interactive mode:
+
+> radio_work add test
+1
+<3>EXT-RADIO-WORK-START 1
+> radio_work show
+ext:test@wlan0:0:1:2.487797
+> radio_work done 1
+OK
+> radio_work show
+
+
+> radio_work done 3
+OK
+> radio_work show
+ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483
+<3>EXT-RADIO-WORK-TIMEOUT 2
+
+
+> radio_work add test2 freq=2412 timeout=60
+5
+<3>EXT-RADIO-WORK-START 5
+> radio_work add test3
+6
+> radio_work add test4
+7
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844
+ext:test3@wlan0:0:0:5.071812
+ext:test4@wlan0:0:0:3.143870
+> radio_work done 6
+OK
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869
+ext:test4@wlan0:0:0:9.679895
+> radio_work done 5
+OK
+<3>EXT-RADIO-WORK-START 7
+<3>EXT-RADIO-WORK-TIMEOUT 7
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 5669c55..ad29ef7 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -109,6 +109,8 @@
 #
 # credential fields:
 #
+# temporary: Whether this credential is temporary and not to be saved
+#
 # priority: Priority group
 #	By default, all networks and credentials get the same priority group
 #	(0). This field can be used to give higher priority for credentials
@@ -166,9 +168,25 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain_suffix_match: Constraint for server domain name
+#	If set, this FQDN is used as a suffix match requirement for the AAA
+#	server certificate in SubjectAltName dNSName element(s). If a
+#	matching dNSName is found, this constraint is met. If no dNSName
+#	values are present, this constraint is matched against SubjetName CN
+#	using same suffix match comparison. Suffix match here means that the
+#	host/domain name is compared one label at a time starting from the
+#	top-level domain and all the labels in @domain_suffix_match shall be
+#	included in the certificate. The certificate may include additional
+#	sub-level labels in addition to the required labels.
+#
+#	For example, domain_suffix_match=example.com would match
+#	test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
@@ -203,6 +221,7 @@
 #	password="password"
 #	ca_cert="/etc/wpa_supplicant/ca.pem"
 #	domain="example.com"
+#	domain_suffix_match="example.com"
 #}
 #
 #cred={
@@ -252,6 +271,8 @@
 OK
 > set_cred 0 priority 1
 OK
+> set_cred 0 temporary 1
+OK
 
 Add a SIM credential using a simulated SIM/USIM card for testing:
 
@@ -267,6 +288,17 @@
 Note: the return value of add_cred is used as the first argument to
 the following set_cred commands.
 
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
 
 Add a WPA2-Enterprise network:
 
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 76f8219..bfad501 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -72,7 +72,8 @@
 Device Discovery
 
 p2p_find [timeout in seconds] [type=<social|progressive>] \
-	[dev_id=<addr>] [delay=<search delay in ms>]
+	[dev_id=<addr>] [dev_type=<device type>] \
+	[delay=<search delay in ms>]
 
 The default behavior is to run a single full scan in the beginning and
 then scan only social channels. type=social will scan only social
@@ -87,6 +88,10 @@
 delay to be used between search iterations (e.g., to free up radio
 resources for concurrent operations).
 
+The optional dev_type option can be used to specify a single device type
+(primary or secondary) to search for, e.g.,
+"p2p_find dev_type=1-0050F204-1".
+
 p2p_listen [timeout in seconds]
 
 Start Listen-only state (become discoverable without searching for
@@ -125,7 +130,7 @@
 
 p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
 	[persistent|persistent=<network id>] [join|auth]
-	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
+	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc]
 
 Start P2P group formation with a discovered P2P peer. This includes
 optional group owner negotiation, group interface setup, provisioning,
@@ -166,7 +171,8 @@
 P2P implementations that require this to allow the user to accept the
 connection.
 
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+	[ht40] [vht]
 
 Set up a P2P group owner manually (i.e., without group owner
 negotiation with a specific peer). This is also known as autonomous
@@ -224,9 +230,8 @@
 peers (note: this can result in long response frames). The pending
 requests are sent during device discovery (see p2p_find).
 
-Only a single pending wildcard query is supported, but there can be
-multiple pending peer device specific queries (each will be sent in
-sequence whenever the peer is found).
+There can be multiple pending peer device specific queries (each will be
+sent in sequence whenever the peer is found).
 
 This command returns an identifier for the pending query (e.g.,
 "1f77628") that can be used to cancel the request. Directed requests
@@ -373,7 +378,8 @@
 Invitation
 
 p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
-	[go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
+	[go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+	[pref=<MHz>]
 
 Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
 persistent group (e.g., persistent=4). If the peer device is the GO of
@@ -416,9 +422,11 @@
 Send a P2P Presence Request to the GO (this is only available when
 acting as a P2P client). If no duration/interval pairs are given, the
 request indicates that this client has no special needs for GO
-presence. the first parameter pair gives the preferred duration and
+presence. The first parameter pair gives the preferred duration and
 interval values in microseconds. If the second pair is included, that
-indicates which value would be acceptable.
+indicates which value would be acceptable. This command returns OK
+immediately and the response from the GO is indicated in a
+P2P-PRESENCE-RESPONSE event message.
 
 Parameters
 
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 3d07109..18b0cca 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -366,11 +366,11 @@
 token is used to enable enrollment of a new station (that was the source
 of the NFC password token).
 
-"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
-contents of a Handover Request Message for connection handover. The
-first argument selects the format of the output data and the second
-argument selects which type of connection handover is requested (WPS =
-Wi-Fi handover as specified in WSC 2.0).
+"nfc_get_handover_req <NDEF> <WPS-CR>" command can be used to build the
+WPS carrier record for a Handover Request Message for connection
+handover. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS-CR = Wi-Fi handover as specified in WSC 2.0).
 
 "nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to
 build the contents of a Handover Select Message for connection handover
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 8b3d6b4..184b41e 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -20,63 +20,6 @@
 # used to fix build issues on such systems (krb5.h not found).
 #CFLAGS += -I/usr/include/kerberos
 
-# Example configuration for various cross-compilation platforms
-
-#### sveasoft (e.g., for Linksys WRT54G) ######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
-#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
-###############################################################################
-
-#### openwrt (e.g., for Linksys WRT54G) #######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
-#	-I../WRT54GS/release/src/include
-#LIBS = -lssl
-###############################################################################
-
-
-# Driver interface for Host AP driver
-#CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for Agere driver
-#CONFIG_DRIVER_HERMES=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
-#CFLAGS += -I../../include/wireless
-
-# Driver interface for madwifi driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_MADWIFI=y
-# Set include directory to the madwifi source tree
-#CFLAGS += -I../../madwifi
-
-# Driver interface for ndiswrapper
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_NDISWRAPPER=y
-
-# Driver interface for Atmel driver
-#CONFIG_DRIVER_ATMEL=y
-
-# Driver interface for old Broadcom driver
-# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
-# Linux wireless extensions and does not need (or even work) with the old
-# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
-#CONFIG_DRIVER_BROADCOM=y
-# Example path for wlioctl.h; change to match your configuration
-#CFLAGS += -I/opt/WRT54GS/release/src/include
-
-# Driver interface for Intel ipw2100/2200 driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_IPW=y
-
-# Driver interface for Ralink driver
-#CONFIG_DRIVER_RALINK=y
-
 # Driver interface for generic Linux wireless extensions
 # Note: WEXT is deprecated in the current Linux kernel version and no new
 # functionality is added to it. nl80211-based interface is the new
@@ -305,7 +248,6 @@
 # Select event loop implementation
 # eloop = select() loop (default)
 # eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
 CONFIG_ELOOP=eloop
 
 # Should we use poll instead of select? Select is used by default.
@@ -325,7 +267,7 @@
 
 # IEEE 802.11w (management frame protection), also known as PMF
 # Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
 
 # Select TLS implementation
 # openssl = OpenSSL (default)
@@ -403,7 +345,7 @@
 #CONFIG_DYNAMIC_EAP_METHODS=y
 
 # IEEE Std 802.11r-2008 (Fast BSS Transition)
-#CONFIG_IEEE80211R=y
+CONFIG_IEEE80211R=y
 
 # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
 #CONFIG_DEBUG_FILE=y
@@ -484,16 +426,16 @@
 
 # Wireless Network Management (IEEE Std 802.11v-2011)
 # Note: This is experimental and not complete implementation.
-#CONFIG_WNM=y
+CONFIG_WNM=y
 
 # Interworking (IEEE 802.11u)
 # This can be used to enable functionality to improve interworking with
 # external networks (GAS/ANQP to learn more about the networks and network
 # selection based on available credentials).
-#CONFIG_INTERWORKING=y
+CONFIG_INTERWORKING=y
 
 # Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
 
 # Disable roaming in wpa_supplicant
 CONFIG_NO_ROAMING=y
@@ -510,14 +452,17 @@
 # more information on P2P operations.
 CONFIG_P2P=y
 
+# Enable TDLS support
 CONFIG_TDLS=y
 
-#Enable Wifi Display
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
 CONFIG_WIFI_DISPLAY=y
 
 # Autoscan
 # This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
 #
 # Enabling directly a module will enable autoscan support.
 # For exponential module:
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fdbe248..f150679 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -15,6 +15,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "eapol_supp/eapol_supp_sm.h"
+#include "crypto/dh_group5.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
@@ -42,11 +43,38 @@
 #endif /* CONFIG_WPS */
 
 
+#ifdef CONFIG_IEEE80211N
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+			     struct hostapd_config *conf,
+			     struct hostapd_hw_modes *mode)
+{
+	u8 center_chan = 0;
+	u8 channel = conf->channel;
+
+	if (!conf->secondary_channel)
+		goto no_vht;
+
+	center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+	if (!center_chan)
+		goto no_vht;
+
+	/* Use 80 MHz channel */
+	conf->vht_oper_chwidth = 1;
+	conf->vht_oper_centr_freq_seg0_idx = center_chan;
+	return;
+
+no_vht:
+	conf->vht_oper_centr_freq_seg0_idx =
+		channel + conf->secondary_channel * 2;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid,
 				  struct hostapd_config *conf)
 {
-	struct hostapd_bss_config *bss = &conf->bss[0];
+	struct hostapd_bss_config *bss = conf->bss[0];
 
 	conf->driver = wpa_s->driver;
 
@@ -114,6 +142,11 @@
 				 HT_CAP_INFO_SHORT_GI40MHZ |
 				 HT_CAP_INFO_RX_STBC_MASK |
 				 HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+			if (mode->vht_capab && ssid->vht) {
+				conf->ieee80211ac = 1;
+				wpas_conf_ap_vht(wpa_s, conf, mode);
+			}
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
@@ -149,6 +182,16 @@
 
 	bss->isolate = !wpa_s->conf->p2p_intra_bss;
 	bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
+
+	if (ssid->p2p_group) {
+		os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4);
+		os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask,
+			  4);
+		os_memcpy(bss->ip_addr_start,
+			  wpa_s->parent->conf->ip_addr_start, 4);
+		os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end,
+			  4);
+	}
 #endif /* CONFIG_P2P */
 
 	if (ssid->ssid_len == 0) {
@@ -244,7 +287,9 @@
 
 	if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
 	    (bss->wpa_group == WPA_CIPHER_CCMP ||
-	     bss->wpa_group == WPA_CIPHER_GCMP)) {
+	     bss->wpa_group == WPA_CIPHER_GCMP ||
+	     bss->wpa_group == WPA_CIPHER_CCMP_256 ||
+	     bss->wpa_group == WPA_CIPHER_GCMP_256)) {
 		/*
 		 * Strong ciphers do not need frequent rekeying, so increase
 		 * the default GTK rekeying period to 24 hours.
@@ -326,6 +371,8 @@
 	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
 	if (hdr_len > len)
 		return;
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+		return;
 	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
 			   mgmt->u.action.category,
 			   &mgmt->u.action.u.vs_public_action.action,
@@ -458,17 +505,13 @@
 	params.ssid = ssid->ssid;
 	params.ssid_len = ssid->ssid_len;
 	switch (ssid->mode) {
-	case WPAS_MODE_INFRA:
-		params.mode = IEEE80211_MODE_INFRA;
-		break;
-	case WPAS_MODE_IBSS:
-		params.mode = IEEE80211_MODE_IBSS;
-		break;
 	case WPAS_MODE_AP:
 	case WPAS_MODE_P2P_GO:
 	case WPAS_MODE_P2P_GROUP_FORMATION:
 		params.mode = IEEE80211_MODE_AP;
 		break;
+	default:
+		return -1;
 	}
 	if (ssid->frequency == 0)
 		ssid->frequency = 2462; /* default channel 11 */
@@ -479,7 +522,7 @@
 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
 	else
 		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
-	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+	params.key_mgmt_suite = wpa_s->key_mgmt;
 
 	wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
 							  1);
@@ -488,8 +531,7 @@
 			   "cipher.");
 		return -1;
 	}
-	params.pairwise_suite =
-		wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
+	params.pairwise_suite = wpa_s->pairwise_cipher;
 	params.group_suite = params.pairwise_suite;
 
 #ifdef CONFIG_P2P
@@ -500,6 +542,8 @@
 
 	if (wpa_s->parent->set_ap_uapsd)
 		params.uapsd = wpa_s->parent->ap_uapsd;
+	else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+		params.uapsd = 1; /* mandatory for P2P GO */
 	else
 		params.uapsd = -1;
 
@@ -529,8 +573,8 @@
 		  sizeof(wpa_s->conf->wmm_ac_params));
 
 	if (params.uapsd > 0) {
-		conf->bss->wmm_enabled = 1;
-		conf->bss->wmm_uapsd = 1;
+		conf->bss[0]->wmm_enabled = 1;
+		conf->bss[0]->wmm_uapsd = 1;
 	}
 
 	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
@@ -541,9 +585,9 @@
 
 #ifdef CONFIG_P2P
 	if (ssid->mode == WPAS_MODE_P2P_GO)
-		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+		conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
 	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
-		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+		conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
 			P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
@@ -558,7 +602,7 @@
 	for (i = 0; i < conf->num_bss; i++) {
 		hapd_iface->bss[i] =
 			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
+					       conf->bss[i]);
 		if (hapd_iface->bss[i] == NULL) {
 			wpa_supplicant_ap_deinit(wpa_s);
 			return -1;
@@ -647,6 +691,8 @@
 {
 #ifdef NEED_AP_MLME
 	struct wpa_supplicant *wpa_s = ctx;
+	if (!wpa_s->ap_iface)
+		return;
 	hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
 #endif /* NEED_AP_MLME */
 }
@@ -909,6 +955,19 @@
 	return hostapd_wps_nfc_hs_cr(hapd, ndef);
 }
 
+
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel)
+{
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	hapd = wpa_s->ap_iface->bss[0];
+	return hostapd_wps_nfc_report_handover(hapd, req, sel);
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 #endif /* CONFIG_WPS */
@@ -1010,9 +1069,9 @@
 
 #ifdef CONFIG_P2P
 	if (ssid->mode == WPAS_MODE_P2P_GO)
-		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+		iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
 	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
-		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+		iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
 			P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
@@ -1026,14 +1085,40 @@
 }
 
 
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+		      struct csa_settings *settings)
+{
+#ifdef NEED_AP_MLME
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+		return -1;
+
+	return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+#else /* NEED_AP_MLME */
+	return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
+{
+	struct csa_settings settings;
+	int ret = hostapd_parse_csa_settings(pos, &settings);
+
+	if (ret)
+		return ret;
+
+	return ap_switch_channel(wpa_s, &settings);
+}
+
+
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset)
+		       int offset, int width, int cf1, int cf2)
 {
 	if (!wpa_s->ap_iface)
 		return;
 
 	wpa_s->assoc_freq = freq;
-	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
 }
 
 
@@ -1076,3 +1161,48 @@
 
 	return 0;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
+			   const struct wpabuf *pw, const u8 *pubkey_hash)
+{
+	struct hostapd_data *hapd;
+	struct wps_context *wps;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+	hapd = wpa_s->ap_iface->bss[0];
+	wps = hapd->wps;
+
+	if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL ||
+	    wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
+		return -1;
+	}
+
+	dh5_free(wps->dh_ctx);
+	wpabuf_free(wps->dh_pubkey);
+	wpabuf_free(wps->dh_privkey);
+	wps->dh_privkey = wpabuf_dup(
+		wpa_s->parent->conf->wps_nfc_dh_privkey);
+	wps->dh_pubkey = wpabuf_dup(
+		wpa_s->parent->conf->wps_nfc_dh_pubkey);
+	if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+		wps->dh_ctx = NULL;
+		wpabuf_free(wps->dh_pubkey);
+		wps->dh_pubkey = NULL;
+		wpabuf_free(wps->dh_privkey);
+		wps->dh_privkey = NULL;
+		return -1;
+	}
+	wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+	if (wps->dh_ctx == NULL)
+		return -1;
+
+	return wps_registrar_add_nfc_pw_token(hapd->wps->registrar, pubkey_hash,
+					      pw_id,
+					      pw ? wpabuf_head(pw) : NULL,
+					      pw ? wpabuf_len(pw) : 0, 1);
+}
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 74a0b18..8aa5ffa 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -50,8 +50,11 @@
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
 				      const u8 *addr);
 void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+		      struct csa_settings *settings);
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset);
+		       int offset, int width, int cf1, int cf2);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					     int ndef);
 #ifdef CONFIG_AP
@@ -66,4 +69,10 @@
 }
 #endif /* CONFIG_AP */
 
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel);
+int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
+			   const struct wpabuf *pw, const u8 *pubkey_hash);
+
 #endif /* AP_H */
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 9a9bd52..f74cdbf 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -31,9 +31,9 @@
 };
 
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name)
 {
-	const char *name = ssid->bgscan;
 	const char *params;
 	size_t nlen;
 	int i;
@@ -41,7 +41,7 @@
 
 	bgscan_deinit(wpa_s);
 	if (name == NULL)
-		return 0;
+		return -1;
 
 	params = os_strchr(name, ':');
 	if (params == NULL) {
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index e9d15fc..9131e4e 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -29,7 +29,8 @@
 
 #ifdef CONFIG_BGSCAN
 
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		const char *name);
 void bgscan_deinit(struct wpa_supplicant *wpa_s);
 int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
@@ -41,7 +42,7 @@
 #else /* CONFIG_BGSCAN */
 
 static inline int bgscan_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid)
+			      struct wpa_ssid *ssid, const char name)
 {
 	return 0;
 }
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index 07d31e4..6a92b73 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -34,7 +34,7 @@
 	int signal_threshold;
 	int short_interval; /* use if signal < threshold */
 	int long_interval; /* use if signal > threshold */
-	struct os_time last_bgscan;
+	struct os_reltime last_bgscan;
 	char *fname;
 	struct dl_list bss;
 	int *supp_freqs;
@@ -240,17 +240,14 @@
 	if (data->supp_freqs == NULL)
 		return freqs;
 
-	idx = data->probe_idx + 1;
-	while (idx != data->probe_idx) {
-		if (data->supp_freqs[idx] == 0) {
-			if (data->probe_idx == 0)
-				break;
-			idx = 0;
-		}
+	idx = data->probe_idx;
+	do {
 		if (!in_array(freqs, data->supp_freqs[idx])) {
 			wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
 				   "%u", data->supp_freqs[idx]);
-			data->probe_idx = idx;
+			data->probe_idx = idx + 1;
+			if (data->supp_freqs[data->probe_idx] == 0)
+				data->probe_idx = 0;
 			n = os_realloc_array(freqs, count + 2, sizeof(int));
 			if (n == NULL)
 				return freqs;
@@ -262,7 +259,9 @@
 		}
 
 		idx++;
-	}
+		if (data->supp_freqs[idx] == 0)
+			idx = 0;
+	} while (idx != data->probe_idx);
 
 	return freqs;
 }
@@ -311,7 +310,7 @@
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_learn_timeout, data, NULL);
 	} else
-		os_get_time(&data->last_bgscan);
+		os_get_reltime(&data->last_bgscan);
 	os_free(freqs);
 }
 
@@ -363,6 +362,9 @@
 		for (j = 0; j < modes[i].num_channels; j++) {
 			if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
+			/* some hw modes (e.g. 11b & 11g) contain same freqs */
+			if (in_array(freqs, modes[i].channels[j].freq))
+				continue;
 			n = os_realloc_array(freqs, count + 2, sizeof(int));
 			if (n == NULL)
 				continue;
@@ -419,6 +421,14 @@
 
 	data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
 	data->scan_interval = data->short_interval;
+	if (data->signal_threshold) {
+		/* Poll for signal info to set initial scan interval */
+		struct wpa_signal_info siginfo;
+		if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+		    siginfo.current_signal >= data->signal_threshold)
+			data->scan_interval = data->long_interval;
+	}
+
 	eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
 			       data, NULL);
 
@@ -428,7 +438,7 @@
 	 * us skip an immediate new scan in cases where the current signal
 	 * level is below the bgscan threshold.
 	 */
-	os_get_time(&data->last_bgscan);
+	os_get_reltime(&data->last_bgscan);
 
 	return data;
 }
@@ -555,7 +565,7 @@
 {
 	struct bgscan_learn_data *data = priv;
 	int scan = 0;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (data->short_interval == data->long_interval ||
 	    data->signal_threshold == 0)
@@ -569,7 +579,7 @@
 		wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
 			   "interval");
 		data->scan_interval = data->short_interval;
-		os_get_time(&now);
+		os_get_reltime(&now);
 		if (now.sec > data->last_bgscan.sec + 1)
 			scan = 1;
 	} else if (data->scan_interval == data->short_interval && above) {
@@ -584,7 +594,7 @@
 		 * Signal dropped further 4 dB. Request a new scan if we have
 		 * not yet scanned in a while.
 		 */
-		os_get_time(&now);
+		os_get_reltime(&now);
 		if (now.sec > data->last_bgscan.sec + 10)
 			scan = 1;
 	}
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 479f703..a467cc5 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -26,7 +26,7 @@
 	int max_short_scans; /* maximum times we short-scan before back-off */
 	int short_interval; /* use if signal < threshold */
 	int long_interval; /* use if signal > threshold */
-	struct os_time last_bgscan;
+	struct os_reltime last_bgscan;
 };
 
 
@@ -75,7 +75,7 @@
 			 */
 			data->short_scan_count--;
 		}
-		os_get_time(&data->last_bgscan);
+		os_get_reltime(&data->last_bgscan);
 	}
 }
 
@@ -159,7 +159,7 @@
 	 * us skip an immediate new scan in cases where the current signal
 	 * level is below the bgscan threshold.
 	 */
-	os_get_time(&data->last_bgscan);
+	os_get_reltime(&data->last_bgscan);
 
 	return data;
 }
@@ -211,7 +211,7 @@
 {
 	struct bgscan_simple_data *data = priv;
 	int scan = 0;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (data->short_interval == data->long_interval ||
 	    data->signal_threshold == 0)
@@ -225,7 +225,7 @@
 		wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
 			   "bgscan interval");
 		data->scan_interval = data->short_interval;
-		os_get_time(&now);
+		os_get_reltime(&now);
 		if (now.sec > data->last_bgscan.sec + 1 &&
 		    data->short_scan_count <= data->max_short_scans)
 			/*
@@ -259,7 +259,7 @@
 		 * Signal dropped further 4 dB. Request a new scan if we have
 		 * not yet scanned in a while.
 		 */
-		os_get_time(&now);
+		os_get_reltime(&now);
 		if (now.sec > data->last_bgscan.sec + 10)
 			scan = 1;
 	}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 67a9f97..9ea6903 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -224,9 +224,9 @@
 }
 
 
-static void calculate_update_time(const struct os_time *fetch_time,
+static void calculate_update_time(const struct os_reltime *fetch_time,
 				  unsigned int age_ms,
-				  struct os_time *update_time)
+				  struct os_reltime *update_time)
 {
 	os_time_t usec;
 
@@ -243,7 +243,7 @@
 
 
 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
-			     struct os_time *fetch_time)
+			     struct os_reltime *fetch_time)
 {
 	dst->flags = src->flags;
 	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
@@ -326,7 +326,7 @@
 static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
 				    const u8 *ssid, size_t ssid_len,
 				    struct wpa_scan_res *res,
-				    struct os_time *fetch_time)
+				    struct os_reltime *fetch_time)
 {
 	struct wpa_bss *bss;
 
@@ -492,7 +492,7 @@
 
 static struct wpa_bss *
 wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-	       struct wpa_scan_res *res, struct os_time *fetch_time)
+	       struct wpa_scan_res *res, struct os_reltime *fetch_time)
 {
 	u32 changes;
 
@@ -502,6 +502,22 @@
 	wpa_bss_copy_res(bss, res, fetch_time);
 	/* Move the entry to the end of the list */
 	dl_list_del(&bss->list);
+#ifdef CONFIG_P2P
+	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+	    !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
+		/*
+		 * This can happen when non-P2P station interface runs a scan
+		 * without P2P IE in the Probe Request frame. P2P GO would reply
+		 * to that with a Probe Response that does not include P2P IE.
+		 * Do not update the IEs in this BSS entry to avoid such loss of
+		 * information that may be needed for P2P operations to
+		 * determine group information.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
+			MACSTR " since that would remove P2P IE information",
+			MAC2STR(bss->bssid));
+	} else
+#endif /* CONFIG_P2P */
 	if (bss->ie_len + bss->beacon_ie_len >=
 	    res->ie_len + res->beacon_ie_len) {
 		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
@@ -571,17 +587,18 @@
  */
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_res *res,
-			     struct os_time *fetch_time)
+			     struct os_reltime *fetch_time)
 {
 	const u8 *ssid, *p2p;
 	struct wpa_bss *bss;
 
 	if (wpa_s->conf->ignore_old_scan_res) {
-		struct os_time update;
+		struct os_reltime update;
 		calculate_update_time(fetch_time, res->age, &update);
-		if (os_time_before(&update, &wpa_s->scan_trigger_time)) {
-			struct os_time age;
-			os_time_sub(&wpa_s->scan_trigger_time, &update, &age);
+		if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
+			struct os_reltime age;
+			os_reltime_sub(&wpa_s->scan_trigger_time, &update,
+				       &age);
 			wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
 				"table entry that is %u.%06u seconds older "
 				"than our scan trigger",
@@ -625,8 +642,18 @@
 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
 	if (bss == NULL)
 		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
-	else
+	else {
 		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+		if (wpa_s->last_scan_res) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (bss == wpa_s->last_scan_res[i]) {
+					/* Already in the list */
+					return;
+				}
+			}
+		}
+	}
 
 	if (bss == NULL)
 		return;
@@ -705,26 +732,10 @@
 {
 	struct wpa_bss *bss, *n;
 
-	wpa_s->last_scan_full = 0;
-	os_get_time(&wpa_s->last_scan);
+	os_get_reltime(&wpa_s->last_scan);
 	if (!new_scan)
 		return; /* do not expire entries without new scan */
 
-	if (info && !info->aborted && !info->freqs) {
-		size_t i;
-		if (info->num_ssids == 0) {
-			wpa_s->last_scan_full = 1;
-		} else {
-			for (i = 0; i < info->num_ssids; i++) {
-				if (info->ssids[i].ssid == NULL ||
-				    info->ssids[i].ssid_len == 0) {
-					wpa_s->last_scan_full = 1;
-					break;
-				}
-			}
-		}
-	}
-
 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
 		if (wpa_bss_in_use(wpa_s, bss))
 			continue;
@@ -738,10 +749,8 @@
 		}
 	}
 
-	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
-		   "last_scan_full=%d",
-		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
-		   wpa_s->last_scan_full);
+	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
 }
 
 
@@ -755,19 +764,19 @@
 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
 {
 	struct wpa_bss *bss, *n;
-	struct os_time t;
+	struct os_reltime t;
 
 	if (dl_list_empty(&wpa_s->bss))
 		return;
 
-	os_get_time(&t);
+	os_get_reltime(&t);
 	t.sec -= age;
 
 	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
 		if (wpa_bss_in_use(wpa_s, bss))
 			continue;
 
-		if (os_time_before(&bss->last_update, &t)) {
+		if (os_reltime_before(&bss->last_update, &t)) {
 			wpa_bss_remove(wpa_s, bss, __func__);
 		} else
 			break;
@@ -811,6 +820,8 @@
 {
 	struct wpa_bss *bss, *n;
 
+	wpa_s->clear_driver_scan_cache = 1;
+
 	if (wpa_s->bss.next == NULL)
 		return; /* BSS table not yet initialized */
 
@@ -874,7 +885,7 @@
 		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
 			continue;
 		if (found == NULL ||
-		    os_time_before(&found->last_update, &bss->last_update))
+		    os_reltime_before(&found->last_update, &bss->last_update))
 			found = bss;
 	}
 	return found;
@@ -1002,6 +1013,43 @@
 
 
 /**
+ * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ *
+ * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+					u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	if (bss->beacon_ie_len == 0)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	pos += bss->ie_len;
+	end = pos + bss->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
  * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
  * @bss: BSS table entry
  * @vendor_type: Vendor type (four octets starting the IE payload)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 2b41948..4deeb5f 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -84,7 +84,7 @@
 	/** Timestamp of last Beacon/Probe Response frame */
 	u64 tsf;
 	/** Time of the last update (i.e., Beacon or Probe Response RX) */
-	struct os_time last_update;
+	struct os_reltime last_update;
 	/** ANQP data */
 	struct wpa_bss_anqp *anqp;
 	/** Length of the following IE field in octets (from Probe Response) */
@@ -98,7 +98,7 @@
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_res *res,
-			     struct os_time *fetch_time);
+			     struct os_reltime *fetch_time);
 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
 			int new_scan);
 int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -118,6 +118,8 @@
 				      unsigned int idf, unsigned int idl);
 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+					u32 vendor_type);
 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
 					    u32 vendor_type);
 struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 69f920d..2dd7054 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "utils/uuid.h"
+#include "utils/ip_addr.h"
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
@@ -546,10 +547,10 @@
 	char *buf, *pos, *end;
 	int ret;
 
-	pos = buf = os_zalloc(50);
+	pos = buf = os_zalloc(100);
 	if (buf == NULL)
 		return NULL;
-	end = buf + 50;
+	end = buf + 100;
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
@@ -602,29 +603,59 @@
 	}
 
 #ifdef CONFIG_IEEE80211R
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
-		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sFT-PSK",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sFT-EAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_WPS
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-		pos += os_snprintf(pos, end - pos, "%sWPS",
-				   pos == buf ? "" : " ");
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		ret = os_snprintf(pos, end - pos, "%sWPS",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
 #endif /* CONFIG_WPS */
 
 	return buf;
@@ -873,6 +904,10 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(ssid->scan_freq);
 	ssid->scan_freq = freqs;
 
@@ -889,6 +924,10 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(ssid->freq_list);
 	ssid->freq_list = freqs;
 
@@ -1283,6 +1322,52 @@
 
 #ifdef CONFIG_P2P
 
+static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+	    os_strcmp(value, "any") == 0) {
+		os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
+		wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
+		return 0;
+	}
+	if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
+			   line, value);
+		return -1;
+	}
+	ssid->bssid_set = 1;
+	wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
+		   MAC2STR(ssid->go_p2p_dev_addr));
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	char *value;
+	int res;
+
+	if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
+		return NULL;
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
 static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
 					    struct wpa_ssid *ssid, int line,
 					    const char *value)
@@ -1541,6 +1626,7 @@
 	{ STRe(dh_file) },
 	{ STRe(subject_match) },
 	{ STRe(altsubject_match) },
+	{ STRe(domain_suffix_match) },
 	{ STRe(ca_cert2) },
 	{ STRe(ca_path2) },
 	{ STRe(client_cert2) },
@@ -1549,6 +1635,7 @@
 	{ STRe(dh_file2) },
 	{ STRe(subject_match2) },
 	{ STRe(altsubject_match2) },
+	{ STRe(domain_suffix_match2) },
 	{ STRe(phase1) },
 	{ STRe(phase2) },
 	{ STRe(pcsc) },
@@ -1592,6 +1679,7 @@
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
+	{ FUNC(go_p2p_dev_addr) },
 	{ FUNC(p2p_client_list) },
 	{ FUNC(psk_list) },
 #endif /* CONFIG_P2P */
@@ -1646,7 +1734,7 @@
 #undef _FUNC
 #undef FUNC
 #undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
 
 
 /**
@@ -1748,6 +1836,7 @@
 	os_free(eap->dh_file);
 	os_free(eap->subject_match);
 	os_free(eap->altsubject_match);
+	os_free(eap->domain_suffix_match);
 	os_free(eap->ca_cert2);
 	os_free(eap->ca_path2);
 	os_free(eap->client_cert2);
@@ -1756,6 +1845,7 @@
 	os_free(eap->dh_file2);
 	os_free(eap->subject_match2);
 	os_free(eap->altsubject_match2);
+	os_free(eap->domain_suffix_match2);
 	os_free(eap->phase1);
 	os_free(eap->phase2);
 	os_free(eap->pcsc);
@@ -1773,6 +1863,7 @@
 	os_free(eap->pending_req_otp);
 	os_free(eap->pac_file);
 	os_free(eap->new_password);
+	os_free(eap->external_sim_resp);
 }
 #endif /* IEEE8021X_EAPOL */
 
@@ -1813,6 +1904,8 @@
 
 void wpa_config_free_cred(struct wpa_cred *cred)
 {
+	size_t i;
+
 	os_free(cred->realm);
 	os_free(cred->username);
 	os_free(cred->password);
@@ -1822,7 +1915,10 @@
 	os_free(cred->private_key_passwd);
 	os_free(cred->imsi);
 	os_free(cred->milenage);
+	for (i = 0; i < cred->num_domain; i++)
+		os_free(cred->domain[i]);
 	os_free(cred->domain);
+	os_free(cred->domain_suffix_match);
 	os_free(cred->eap_method);
 	os_free(cred->phase1);
 	os_free(cred->phase2);
@@ -1831,6 +1927,22 @@
 }
 
 
+void wpa_config_flush_blobs(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct wpa_config_blob *blob, *prev;
+
+	blob = config->blobs;
+	config->blobs = NULL;
+	while (blob) {
+		prev = blob;
+		blob = blob->next;
+		wpa_config_free_blob(prev);
+	}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
 /**
  * wpa_config_free - Free configuration data
  * @config: Configuration data from wpa_config_read()
@@ -1840,9 +1952,6 @@
  */
 void wpa_config_free(struct wpa_config *config)
 {
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct wpa_config_blob *blob, *prevblob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
 	struct wpa_ssid *ssid, *prev = NULL;
 	struct wpa_cred *cred, *cprev;
 
@@ -1860,15 +1969,7 @@
 		wpa_config_free_cred(cprev);
 	}
 
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	blob = config->blobs;
-	prevblob = NULL;
-	while (blob) {
-		prevblob = blob;
-		blob = blob->next;
-		wpa_config_free_blob(prevblob);
-	}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
+	wpa_config_flush_blobs(config);
 
 	wpabuf_free(config->wps_vendor_ext_m1);
 	os_free(config->ctrl_interface);
@@ -1888,6 +1989,7 @@
 	os_free(config->p2p_ssid_postfix);
 	os_free(config->pssid);
 	os_free(config->p2p_pref_chan);
+	os_free(config->p2p_no_go_freq.range);
 	os_free(config->autoscan);
 	os_free(config->freq_list);
 	wpabuf_free(config->wps_nfc_dh_pubkey);
@@ -2297,6 +2399,11 @@
 	char *val;
 	size_t len;
 
+	if (os_strcmp(var, "temporary") == 0) {
+		cred->temporary = atoi(value);
+		return 0;
+	}
+
 	if (os_strcmp(var, "priority") == 0) {
 		cred->priority = atoi(value);
 		return 0;
@@ -2394,9 +2501,23 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "domain_suffix_match") == 0) {
+		os_free(cred->domain_suffix_match);
+		cred->domain_suffix_match = val;
+		return 0;
+	}
+
 	if (os_strcmp(var, "domain") == 0) {
-		os_free(cred->domain);
-		cred->domain = val;
+		char **new_domain;
+		new_domain = os_realloc_array(cred->domain,
+					      cred->num_domain + 1,
+					      sizeof(char *));
+		if (new_domain == NULL) {
+			os_free(val);
+			return -1;
+		}
+		new_domain[cred->num_domain++] = val;
+		cred->domain = new_domain;
 		return 0;
 	}
 
@@ -2426,6 +2547,21 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "required_roaming_consortium") == 0) {
+		if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+		{
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "required_roaming_consortium length %d "
+				   "(3..15 expected)", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+		os_memcpy(cred->required_roaming_consortium, val, len);
+		cred->required_roaming_consortium_len = len;
+		os_free(val);
+		return 0;
+	}
+
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		struct excluded_ssid *e;
 
@@ -2770,6 +2906,27 @@
 }
 
 
+static int wpa_config_process_bgscan(const struct global_parse_data *data,
+				     struct wpa_config *config, int line,
+				     const char *pos)
+{
+	size_t len;
+	char *tmp;
+	int res;
+
+	tmp = wpa_config_parse_string(pos, &len);
+	if (tmp == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
+			   line, data->name);
+		return -1;
+	}
+
+	res = wpa_global_config_parse_str(data, config, line, tmp);
+	os_free(tmp);
+	return res;
+}
+
+
 static int wpa_global_config_parse_bin(const struct global_parse_data *data,
 				       struct wpa_config *config, int line,
 				       const char *pos)
@@ -2808,12 +2965,39 @@
 	freqs = wpa_config_parse_int_array(value);
 	if (freqs == NULL)
 		return -1;
+	if (freqs[0] == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
 	os_free(config->freq_list);
 	config->freq_list = freqs;
 	return 0;
 }
 
 
+#ifdef CONFIG_P2P
+static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
+					struct wpa_config *config, int line,
+					const char *pos)
+{
+	u32 *dst;
+	struct hostapd_ip_addr addr;
+
+	if (hostapd_parse_ip_addr(pos, &addr) < 0)
+		return -1;
+	if (addr.af != AF_INET)
+		return -1;
+
+	dst = (u32 *) (((u8 *) config) + (long) data->param1);
+	os_memcpy(dst, &addr.u.v4.s_addr, 4);
+	wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
+		   WPA_GET_BE32((u8 *) dst));
+
+	return 0;
+}
+#endif /* CONFIG_P2P */
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
 				      struct wpa_config *config, int line,
 				      const char *pos)
@@ -2998,6 +3182,26 @@
 	wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
 	return -1;
 }
+
+
+static int wpa_config_process_p2p_no_go_freq(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	int ret;
+
+	ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+		   config->p2p_no_go_freq.num);
+
+	return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -3070,6 +3274,19 @@
 }
 
 
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+	os_free(config->ctrl_interface);
+	config->ctrl_interface = NULL;
+	return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -3085,14 +3302,17 @@
 #define STR(f) _STR(f), NULL, NULL
 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
 #define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+#define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
 	{ STR(ctrl_interface), 0 },
+	{ FUNC_NO_VAR(no_ctrl_interface), 0 },
 	{ STR(ctrl_interface_group), 0 } /* deprecated */,
 #endif /* CONFIG_CTRL_IFACE */
 	{ INT_RANGE(eapol_version, 1, 2), 0 },
 	{ INT(ap_scan), 0 },
+	{ FUNC(bgscan), 0 },
 	{ INT(disable_scan_offload), 0 },
 	{ INT(fast_reauth), 0 },
 	{ STR(opensc_engine_path), 0 },
@@ -3100,6 +3320,7 @@
 	{ STR(pkcs11_module_path), 0 },
 	{ STR(pcsc_reader), 0 },
 	{ STR(pcsc_pin), 0 },
+	{ INT(external_sim), 0 },
 	{ STR(driver_param), 0 },
 	{ INT(dot11RSNAConfigPMKLifetime), 0 },
 	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -3125,18 +3346,25 @@
 	{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
 	{ INT(p2p_listen_reg_class), 0 },
 	{ INT(p2p_listen_channel), 0 },
-	{ INT(p2p_oper_reg_class), 0 },
-	{ INT(p2p_oper_channel), 0 },
+	{ INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+	{ INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
 	{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
 	{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
 	{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
 	{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
 	{ INT(p2p_group_idle), 0 },
 	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+	{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
+	{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
 	{ INT(p2p_go_ht40), 0 },
+	{ INT(p2p_go_vht), 0 },
 	{ INT(p2p_disabled), 0 },
 	{ INT(p2p_no_group_iface), 0 },
 	{ INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
+	{ IPV4(ip_addr_go), 0 },
+	{ IPV4(ip_addr_mask), 0 },
+	{ IPV4(ip_addr_start), 0 },
+	{ IPV4(ip_addr_end), 0 },
 #endif /* CONFIG_P2P */
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
@@ -3183,7 +3411,8 @@
 #undef STR
 #undef STR_RANGE
 #undef BIN
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+#undef IPV4
+#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
 
 
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fe46e3..e7bdaa5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -52,6 +52,11 @@
 	int id;
 
 	/**
+	 * temporary - Whether this credential is temporary and not to be saved
+	 */
+	int temporary;
+
+	/**
 	 * priority - Priority group
 	 *
 	 * By default, all networks and credentials get the same priority group
@@ -150,12 +155,37 @@
 	char *milenage;
 
 	/**
-	 * domain - Home service provider FQDN
+	 * domain_suffix_match - Constraint for server domain name
+	 *
+	 * If set, this FQDN is used as a suffix match requirement for the AAA
+	 * server certificate in SubjectAltName dNSName element(s). If a
+	 * matching dNSName is found, this constraint is met. If no dNSName
+	 * values are present, this constraint is matched against SubjetName CN
+	 * using same suffix match comparison. Suffix match here means that the
+	 * host/domain name is compared one label at a time starting from the
+	 * top-level domain and all the labels in @domain_suffix_match shall be
+	 * included in the certificate. The certificate may include additional
+	 * sub-level labels in addition to the required labels.
+	 *
+	 * For example, domain_suffix_match=example.com would match
+	 * test.example.com but would not match test-example.com.
+	 */
+	char *domain_suffix_match;
+
+	/**
+	 * domain - Home service provider FQDN(s)
 	 *
 	 * This is used to compare against the Domain Name List to figure out
-	 * whether the AP is operated by the Home SP.
+	 * whether the AP is operated by the Home SP. Multiple domain entries
+	 * can be used to configure alternative FQDNs that will be considered
+	 * home networks.
 	 */
-	char *domain;
+	char **domain;
+
+	/**
+	 * num_domain - Number of FQDNs in the domain array
+	 */
+	size_t num_domain;
 
 	/**
 	 * roaming_consortium - Roaming Consortium OI
@@ -175,6 +205,9 @@
 	 */
 	size_t roaming_consortium_len;
 
+	u8 required_roaming_consortium[15];
+	size_t required_roaming_consortium_len;
+
 	/**
 	 * eap_method - EAP method to use
 	 *
@@ -301,6 +334,18 @@
 	int ap_scan;
 
 	/**
+	 * bgscan - Background scan and roaming parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for background scanning and
+	 * roaming within a network (ESS). For more detailed information see
+	 * ssid block documentation.
+	 *
+	 * The variable defines default bgscan behavior for all BSS station
+	 * networks except for those which have their own bgscan configuration.
+	 */
+	 char *bgscan;
+
+	/**
 	 * disable_scan_offload - Disable automatic offloading of scan requests
 	 *
 	 * By default, %wpa_supplicant tries to offload scanning if the driver
@@ -425,6 +470,11 @@
 	char *pcsc_pin;
 
 	/**
+	 * external_sim - Use external processing for SIM/USIM operations
+	 */
+	int external_sim;
+
+	/**
 	 * driver_param - Driver interface parameters
 	 *
 	 * This text string is passed to the selected driver interface with the
@@ -572,6 +622,8 @@
 	int p2p_intra_bss;
 	unsigned int num_p2p_pref_chan;
 	struct p2p_channel *p2p_pref_chan;
+	struct wpa_freq_range_list p2p_no_go_freq;
+	int p2p_add_cli_chan;
 	int p2p_ignore_shared_freq;
 
 	struct wpabuf *wps_vendor_ext_m1;
@@ -793,6 +845,16 @@
 	int p2p_go_ht40;
 
 	/**
+	 * p2p_go_vht - Default mode for VHT enable when operating as GO
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_vht;
+
+	/**
 	 * p2p_disabled - Whether P2P operations are disabled for this interface
 	 */
 	int p2p_disabled;
@@ -884,9 +946,13 @@
 	 * to specify the TDLS link to get established to the driver. The
 	 * driver requests the TDLS setup to the supplicant only for the
 	 * specified TDLS peers.
-	 *
 	 */
 	int tdls_external_control;
+
+	u8 ip_addr_go[4];
+	u8 ip_addr_mask[4];
+	u8 ip_addr_start[4];
+	u8 ip_addr_end[4];
 };
 
 
@@ -918,6 +984,7 @@
 			 struct wpa_config_blob *blob);
 void wpa_config_free_blob(struct wpa_config_blob *blob);
 int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+void wpa_config_flush_blobs(struct wpa_config *config);
 
 struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
 struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index bb0e536..6312a77 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -606,6 +606,15 @@
 
 #ifdef CONFIG_P2P
 
+static void write_go_p2p_dev_addr(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "go_p2p_dev_addr");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tgo_p2p_dev_addr=%s\n", value);
+	os_free(value);
+}
+
 static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
 {
 	char *value = wpa_config_get(ssid, "p2p_client_list");
@@ -653,6 +662,7 @@
 	write_auth_alg(f, ssid);
 	STR(bgscan);
 	STR(autoscan);
+	STR(scan_freq);
 #ifdef IEEE8021X_EAPOL
 	write_eap(f, ssid);
 	STR(identity);
@@ -666,6 +676,7 @@
 	STR(dh_file);
 	STR(subject_match);
 	STR(altsubject_match);
+	STR(domain_suffix_match);
 	STR(ca_cert2);
 	STR(ca_path2);
 	STR(client_cert2);
@@ -674,6 +685,7 @@
 	STR(dh_file2);
 	STR(subject_match2);
 	STR(altsubject_match2);
+	STR(domain_suffix_match2);
 	STR(phase1);
 	STR(phase2);
 	STR(pcsc);
@@ -711,6 +723,7 @@
 #endif /* CONFIG_IEEE80211W */
 	STR(id_str);
 #ifdef CONFIG_P2P
+	write_go_p2p_dev_addr(f, ssid);
 	write_p2p_client_list(f, ssid);
 	write_psk_list(f, ssid);
 #endif /* CONFIG_P2P */
@@ -725,6 +738,8 @@
 
 static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
 {
+	size_t i;
+
 	if (cred->priority)
 		fprintf(f, "\tpriority=%d\n", cred->priority);
 	if (cred->pcsc)
@@ -750,10 +765,12 @@
 		fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
 	if (cred->milenage)
 		fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
-	if (cred->domain)
-		fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+	for (i = 0; i < cred->num_domain; i++)
+		fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+	if (cred->domain_suffix_match)
+		fprintf(f, "\tdomain_suffix_match=\"%s\"",
+			cred->domain_suffix_match);
 	if (cred->roaming_consortium_len) {
-		size_t i;
 		fprintf(f, "\troaming_consortium=");
 		for (i = 0; i < cred->roaming_consortium_len; i++)
 			fprintf(f, "%02x", cred->roaming_consortium[i]);
@@ -770,7 +787,7 @@
 	if (cred->phase2)
 		fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
 	if (cred->excluded_ssid) {
-		size_t i, j;
+		size_t j;
 		for (i = 0; i < cred->num_excluded_ssid; i++) {
 			struct excluded_ssid *e = &cred->excluded_ssid[i];
 			fprintf(f, "\texcluded_ssid=");
@@ -934,8 +951,19 @@
 		}
 		fprintf(f, "\n");
 	}
+	if (config->p2p_no_go_freq.num) {
+		char *val = freq_range_list_str(&config->p2p_no_go_freq);
+		if (val) {
+			fprintf(f, "p2p_no_go_freq=%s\n", val);
+			os_free(val);
+		}
+	}
+	if (config->p2p_add_cli_chan)
+		fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
 	if (config->p2p_go_ht40)
 		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+	if (config->p2p_go_vht)
+		fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
 	if (config->p2p_disabled)
 		fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
 	if (config->p2p_no_group_iface)
@@ -1049,8 +1077,11 @@
 		fprintf(f, "sched_scan_interval=%u\n",
 			config->sched_scan_interval);
 
+	if (config->external_sim)
+		fprintf(f, "external_sim=%d\n", config->external_sim);
+
 	if (config->tdls_external_control)
-		fprintf(f, "tdls_external_control=%u\n",
+		fprintf(f, "tdls_external_control=%d\n",
 			config->tdls_external_control);
 }
 
@@ -1079,6 +1110,8 @@
 	wpa_config_write_global(f, config);
 
 	for (cred = config->cred; cred; cred = cred->next) {
+		if (cred->temporary)
+			continue;
 		fprintf(f, "\ncred={\n");
 		wpa_config_write_cred(f, cred);
 		fprintf(f, "}\n");
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c6ea963..d515030 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -131,6 +131,11 @@
 	int bssid_set;
 
 	/**
+	 * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set
+	 */
+	u8 go_p2p_dev_addr[ETH_ALEN];
+
+	/**
 	 * psk - WPA pre-shared key (256 bits)
 	 */
 	u8 psk[32];
@@ -310,12 +315,13 @@
 	 * 4 = P2P Group Formation (used internally; not in configuration
 	 * files)
 	 *
-	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and
-	 * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
-	 * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
-	 * following network block options: proto=WPA, key_mgmt=WPA-NONE,
-	 * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
-	 * be set (either directly or using ASCII passphrase).
+	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
+	 * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
+	 * (fixed group key TKIP/CCMP) is available for backwards compatibility,
+	 * but its use is deprecated. WPA-None requires following network block
+	 * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
+	 * CCMP, but not both), and psk must also be set (either directly or
+	 * using ASCII passphrase).
 	 */
 	enum wpas_mode {
 		WPAS_MODE_INFRA = 0,
@@ -394,6 +400,8 @@
 
 	int ht40;
 
+	int vht;
+
 	/**
 	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
 	 *
@@ -491,13 +499,6 @@
 	 */
 	int export_keys;
 
-#ifdef ANDROID_P2P
-	/**
-	 * assoc_retry - Number of times association should be retried.
-	 */
-	int assoc_retry;
-#endif
-
 #ifdef CONFIG_HT_OVERRIDES
 	/**
 	 * disable_ht - Disable HT (IEEE 802.11n) for this network
@@ -610,7 +611,7 @@
 	/**
 	 * disabled_until - Network block disabled until this time if non-zero
 	 */
-	struct os_time disabled_until;
+	struct os_reltime disabled_until;
 
 	/**
 	 * parent_cred - Pointer to parent wpa_cred entry
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b5e237..00a1004 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -623,6 +623,9 @@
 	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
 	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
 
+	wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+				   config->external_sim, 0);
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 6335605..e95b55b 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-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, 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 "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/uuid.h"
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -40,8 +41,6 @@
 #include "autoscan.h"
 #include "wnm_sta.h"
 
-extern struct wpa_driver_ops *wpa_drivers[];
-
 static int wpa_supplicant_global_iface_list(struct wpa_global *global,
 					    char *buf, int len);
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@@ -50,12 +49,12 @@
 
 static int pno_start(struct wpa_supplicant *wpa_s)
 {
-	int ret;
+	int ret, interval;
 	size_t i, num_ssid;
 	struct wpa_ssid *ssid;
 	struct wpa_driver_scan_params params;
 
-	if (wpa_s->pno)
+	if (wpa_s->pno || wpa_s->pno_sched_pending)
 		return 0;
 
 	if ((wpa_s->wpa_state > WPA_SCANNING) &&
@@ -65,8 +64,14 @@
 	}
 
 	if (wpa_s->wpa_state == WPA_SCANNING) {
-		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_supplicant_cancel_scan(wpa_s);
+		if (wpa_s->sched_scanning) {
+			wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
+				   "ongoing sched scan");
+			wpa_supplicant_cancel_sched_scan(wpa_s);
+			wpa_s->pno_sched_pending = 1;
+			return 0;
+		}
 	}
 
 	os_memset(&params, 0, sizeof(params));
@@ -114,7 +119,10 @@
 	if (wpa_s->conf->filter_rssi)
 		params.filter_rssi = wpa_s->conf->filter_rssi;
 
-	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+	interval = wpa_s->conf->sched_scan_interval ?
+		wpa_s->conf->sched_scan_interval : 10;
+
+	ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
 	os_free(params.filter_ssids);
 	if (ret == 0)
 		wpa_s->pno = 1;
@@ -126,11 +134,13 @@
 {
 	int ret = 0;
 
-	if (wpa_s->pno) {
+	if (wpa_s->pno || wpa_s->sched_scanning) {
 		wpa_s->pno = 0;
-		ret = wpa_drv_stop_sched_scan(wpa_s);
+		ret = wpa_supplicant_stop_sched_scan(wpa_s);
 	}
 
+	wpa_s->pno_sched_pending = 0;
+
 	if (wpa_s->wpa_state == WPA_SCANNING)
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 
@@ -184,7 +194,7 @@
 	struct wpa_ssid *c;
 
 	/*
-	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
 	 * SSID_SPEC ::= ssid <SSID_HEX>
 	 * BSSID_SPEC ::= bssid <BSSID_HEX>
 	 */
@@ -354,17 +364,21 @@
 		wps_testing_dummy_cred = atoi(value);
 		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
 			   wps_testing_dummy_cred);
+	} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+		wps_corrupt_pkhash = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+			   wps_corrupt_pkhash);
 #endif /* CONFIG_WPS_TESTING */
 	} else if (os_strcasecmp(cmd, "ampdu") == 0) {
 		if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
 			ret = -1;
+#ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
 	} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
 		extern unsigned int tdls_testing;
 		tdls_testing = strtol(value, NULL, 0);
 		wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
 #endif /* CONFIG_TDLS_TESTING */
-#ifdef CONFIG_TDLS
 	} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
 		int disabled = atoi(value);
 		wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
@@ -426,7 +440,11 @@
 		ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
 #ifdef CONFIG_WIFI_DISPLAY
 	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
-		wifi_display_enable(wpa_s->global, !!atoi(value));
+		int enabled = !!atoi(value);
+		if (enabled && !wpa_s->global->p2p)
+			ret = -1;
+		else
+			wifi_display_enable(wpa_s->global, enabled);
 #endif /* CONFIG_WIFI_DISPLAY */
 	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
 		ret = set_bssid_filter(wpa_s, value);
@@ -461,8 +479,13 @@
 					  wpa_s->conf->country[1]);
 #ifdef CONFIG_WIFI_DISPLAY
 	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
-		res = os_snprintf(buf, buflen, "%d",
-				  wpa_s->global->wifi_display);
+		int enabled;
+		if (wpa_s->global->p2p == NULL ||
+		    wpa_s->global->p2p_disabled)
+			enabled = 0;
+		else
+			enabled = wpa_s->global->wifi_display;
+		res = os_snprintf(buf, buflen, "%d", enabled);
 		if (res < 0 || (unsigned int) res >= buflen)
 			return -1;
 		return res;
@@ -569,9 +592,8 @@
 		   MAC2STR(peer));
 
 	if ((wpa_s->conf->tdls_external_control) &&
-	     wpa_tdls_is_external_setup(wpa_s->wpa)) {
+	    wpa_tdls_is_external_setup(wpa_s->wpa))
 		return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
-	}
 
 	wpa_tdls_remove(wpa_s->wpa, peer);
 
@@ -600,9 +622,8 @@
 		   MAC2STR(peer));
 
 	if ((wpa_s->conf->tdls_external_control) &&
-	     wpa_tdls_is_external_setup(wpa_s->wpa)) {
+	    wpa_tdls_is_external_setup(wpa_s->wpa))
 		return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
-	}
 
 	if (wpa_tdls_is_external_setup(wpa_s->wpa))
 		ret = wpa_tdls_teardown_link(
@@ -656,7 +677,7 @@
 	u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
 
-	if (cmd == NULL || os_strcmp(cmd, "any") == 0 || cmd[0] == '\0') {
+	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
 		_bssid = NULL;
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -805,7 +826,8 @@
 	else if (hwaddr_aton(cmd, bssid))
 		return -1;
 
-	return wpas_wps_start_nfc(wpa_s, _bssid);
+	return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
+				  0, 0);
 }
 
 
@@ -877,6 +899,15 @@
 	size_t len;
 	struct wpabuf *buf;
 	int ret;
+	char *freq;
+	int forced_freq = 0;
+
+	freq = strstr(pos, " freq=");
+	if (freq) {
+		*freq = '\0';
+		freq += 6;
+		forced_freq = atoi(freq);
+	}
 
 	len = os_strlen(pos);
 	if (len & 0x01)
@@ -891,7 +922,7 @@
 		return -1;
 	}
 
-	ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+	ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
 	wpabuf_free(buf);
 
 	return ret;
@@ -900,12 +931,12 @@
 
 static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
 					      char *reply, size_t max_len,
-					      int cr)
+					      int ndef)
 {
 	struct wpabuf *buf;
 	int res;
 
-	buf = wpas_wps_nfc_handover_req(wpa_s, cr);
+	buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
 	if (buf == NULL)
 		return -1;
 
@@ -920,25 +951,65 @@
 }
 
 
+#ifdef CONFIG_P2P
+static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len,
+					      int ndef)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
+		return -1;
+	}
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+#endif /* CONFIG_P2P */
+
+
 static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
 					  char *cmd, char *reply,
 					  size_t max_len)
 {
 	char *pos;
+	int ndef;
 
 	pos = os_strchr(cmd, ' ');
 	if (pos == NULL)
 		return -1;
 	*pos++ = '\0';
 
-	if (os_strcmp(cmd, "NDEF") != 0)
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
 		return -1;
 
 	if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+		if (!ndef)
+			return -1;
 		return wpas_ctrl_nfc_get_handover_req_wps(
-			wpa_s, reply, max_len, os_strcmp(pos, "WPS-CR") == 0);
+			wpa_s, reply, max_len, ndef);
 	}
 
+#ifdef CONFIG_P2P
+	if (os_strcmp(pos, "P2P-CR") == 0) {
+		return wpas_ctrl_nfc_get_handover_req_p2p(
+			wpa_s, reply, max_len, ndef);
+	}
+#endif /* CONFIG_P2P */
+
 	return -1;
 }
 
@@ -965,6 +1036,30 @@
 }
 
 
+#ifdef CONFIG_P2P
+static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len,
+					      int ndef, int tag)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+#endif /* CONFIG_P2P */
+
+
 static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
 					  char *cmd, char *reply,
 					  size_t max_len)
@@ -988,40 +1083,26 @@
 	if (pos2)
 		*pos2++ = '\0';
 	if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+		if (!ndef)
+			return -1;
 		return wpas_ctrl_nfc_get_handover_sel_wps(
 			wpa_s, reply, max_len, ndef,
 			os_strcmp(pos, "WPS-CR") == 0, pos2);
 	}
 
-	return -1;
-}
-
-
-static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
-					 char *cmd, char *reply,
-					 size_t max_len)
-{
-	size_t len;
-	struct wpabuf *buf;
-	int ret;
-
-	len = os_strlen(cmd);
-	if (len & 0x01)
-		return -1;
-	len /= 2;
-
-	buf = wpabuf_alloc(len);
-	if (buf == NULL)
-		return -1;
-	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
-		wpabuf_free(buf);
-		return -1;
+#ifdef CONFIG_P2P
+	if (os_strcmp(pos, "P2P-CR") == 0) {
+		return wpas_ctrl_nfc_get_handover_sel_p2p(
+			wpa_s, reply, max_len, ndef, 0);
 	}
 
-	ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
-	wpabuf_free(buf);
+	if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
+		return wpas_ctrl_nfc_get_handover_sel_p2p(
+			wpa_s, reply, max_len, ndef, 1);
+	}
+#endif /* CONFIG_P2P */
 
-	return ret;
+	return -1;
 }
 
 
@@ -1059,39 +1140,62 @@
 	struct wpabuf *req, *sel;
 	int ret;
 	char *pos, *role, *type, *pos2;
+#ifdef CONFIG_P2P
+	char *freq;
+	int forced_freq = 0;
+
+	freq = strstr(cmd, " freq=");
+	if (freq) {
+		*freq = '\0';
+		freq += 6;
+		forced_freq = atoi(freq);
+	}
+#endif /* CONFIG_P2P */
 
 	role = cmd;
 	pos = os_strchr(role, ' ');
-	if (pos == NULL)
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
 		return -1;
+	}
 	*pos++ = '\0';
 
 	type = pos;
 	pos = os_strchr(type, ' ');
-	if (pos == NULL)
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
 		return -1;
+	}
 	*pos++ = '\0';
 
 	pos2 = os_strchr(pos, ' ');
-	if (pos2 == NULL)
+	if (pos2 == NULL) {
+		wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
 		return -1;
+	}
 	*pos2++ = '\0';
 
 	len = os_strlen(pos);
-	if (len & 0x01)
+	if (len & 0x01) {
+		wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
 		return -1;
+	}
 	len /= 2;
 
 	req = wpabuf_alloc(len);
-	if (req == NULL)
+	if (req == NULL) {
+		wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
 		return -1;
+	}
 	if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+		wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
 		wpabuf_free(req);
 		return -1;
 	}
 
 	len = os_strlen(pos2);
 	if (len & 0x01) {
+		wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
 		wpabuf_free(req);
 		return -1;
 	}
@@ -1099,17 +1203,38 @@
 
 	sel = wpabuf_alloc(len);
 	if (sel == NULL) {
+		wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
 		wpabuf_free(req);
 		return -1;
 	}
 	if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+		wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
 		wpabuf_free(req);
 		wpabuf_free(sel);
 		return -1;
 	}
 
+	wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
+		   role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
+
 	if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
 		ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+#ifdef CONFIG_AP
+	} else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
+	{
+		ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
+		if (ret < 0)
+			ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+	} else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+	{
+		ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
+	} else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+	{
+		ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
+						   forced_freq);
+#endif /* CONFIG_P2P */
 	} else {
 		wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
 			   "reported: role=%s type=%s", role, type);
@@ -1118,6 +1243,9 @@
 	wpabuf_free(req);
 	wpabuf_free(sel);
 
+	if (ret)
+		wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
+
 	return ret;
 }
 
@@ -1427,6 +1555,8 @@
 	char *pos, *end, tmp[30];
 	int res, verbose, wps, ret;
 
+	if (os_strcmp(params, "-DRIVER") == 0)
+		return wpa_drv_status(wpa_s, buf, buflen);
 	verbose = os_strcmp(params, "-VERBOSE") == 0;
 	wps = os_strcmp(params, "-WPS") == 0;
 	pos = buf;
@@ -1576,16 +1706,19 @@
 		char *type;
 
 		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			size_t i;
+
 			if (wpa_s->current_ssid->parent_cred != cred)
 				continue;
-			if (!cred->domain)
-				continue;
 
-			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
-					  cred->domain);
-			if (ret < 0 || ret >= end - pos)
-				return pos - buf;
-			pos += ret;
+			for (i = 0; cred->domain && i < cred->num_domain; i++) {
+				ret = os_snprintf(pos, end - pos,
+						  "home_sp=%s\n",
+						  cred->domain[i]);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
 
 			if (wpa_s->current_bss == NULL ||
 			    wpa_s->current_bss->anqp == NULL)
@@ -1623,6 +1756,17 @@
 	if (res >= 0)
 		pos += res;
 
+#ifdef CONFIG_WPS
+	{
+		char uuid_str[100];
+		uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
+		ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_WPS */
+
 #ifdef ANDROID
 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
 		     "id=%d state=%d BSSID=" MACSTR " SSID=%s",
@@ -1631,14 +1775,15 @@
 		     MAC2STR(wpa_s->bssid),
 		     wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
 		     wpa_ssid_txt(wpa_s->current_ssid->ssid,
-		     wpa_s->current_ssid->ssid_len) : "");
+				  wpa_s->current_ssid->ssid_len) : "");
 	if (wpa_s->wpa_state == WPA_COMPLETED) {
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
-		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to "
-			MACSTR " completed %s [id=%d id_str=%s]",
-			MAC2STR(wpa_s->bssid), "(auth)",
-			ssid ? ssid->id : -1,
-			ssid && ssid->id_str ? ssid->id_str : "");
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
+			     "- connection to " MACSTR
+			     " completed %s [id=%d id_str=%s]",
+			     MAC2STR(wpa_s->bssid), "(auth)",
+			     ssid ? ssid->id : -1,
+			     ssid && ssid->id_str ? ssid->id_str : "");
 	}
 #endif /* ANDROID */
 
@@ -1733,9 +1878,6 @@
 }
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_timestamp;
-
 static const char * debug_level_str(int level)
 {
 	switch (level) {
@@ -2046,6 +2188,8 @@
 	const u8 *ie, *ie2, *p2p;
 
 	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+	if (!p2p)
+		p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
 	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
 	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
 	    0)
@@ -2476,7 +2620,7 @@
 		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
 				  cred->id, cred->realm ? cred->realm : "",
 				  cred->username ? cred->username : "",
-				  cred->domain ? cred->domain : "",
+				  cred->domain ? cred->domain[0] : "",
 				  cred->imsi ? cred->imsi : "");
 		if (ret < 0 || ret >= end - pos)
 			return pos - buf;
@@ -2561,9 +2705,16 @@
 		while (cred) {
 			prev = cred;
 			cred = cred->next;
-			if (prev->domain &&
-			    os_strcmp(prev->domain, cmd + 8) == 0)
-				wpas_ctrl_remove_cred(wpa_s, prev);
+			if (prev->domain) {
+				size_t i;
+				for (i = 0; i < prev->num_domain; i++) {
+					if (os_strcmp(prev->domain[i], cmd + 8)
+					    != 0)
+						continue;
+					wpas_ctrl_remove_cred(wpa_s, prev);
+					break;
+				}
+			}
 		}
 		return 0;
 	}
@@ -2642,6 +2793,24 @@
 #endif /* CONFIG_NO_CONFIG_WRITE */
 
 
+struct cipher_info {
+	unsigned int capa;
+	const char *name;
+	int group_only;
+};
+
+static const struct cipher_info ciphers[] = {
+	{ WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
+	{ WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
+	{ WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
+	{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+	{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+	{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+	{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
+	{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+};
+
+
 static int ctrl_iface_get_capability_pairwise(int res, char *strict,
 					      struct wpa_driver_capa *capa,
 					      char *buf, size_t buflen)
@@ -2649,6 +2818,7 @@
 	int ret, first = 1;
 	char *pos, *end;
 	size_t len;
+	unsigned int i;
 
 	pos = buf;
 	end = pos + buflen;
@@ -2662,36 +2832,15 @@
 		return len;
 	}
 
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
+	for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+		if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
+			ret = os_snprintf(pos, end - pos, "%s%s",
+					  first ? "" : " ", ciphers[i].name);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+			first = 0;
+		}
 	}
 
 	return pos - buf;
@@ -2705,6 +2854,7 @@
 	int ret, first = 1;
 	char *pos, *end;
 	size_t len;
+	unsigned int i;
 
 	pos = buf;
 	end = pos + buflen;
@@ -2718,45 +2868,15 @@
 		return len;
 	}
 
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-		ret = os_snprintf(pos, end - pos, "%sWEP104",
-				  first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
+	for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+		if (capa->enc & ciphers[i].capa) {
+			ret = os_snprintf(pos, end - pos, "%s%s",
+					  first ? "" : " ", ciphers[i].name);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+			first = 0;
+		}
 	}
 
 	return pos - buf;
@@ -3033,10 +3153,13 @@
 		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
 			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
-			ret = os_snprintf(pos, end - pos, " %d = %d MHz%s\n",
+			ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
 					  chnl[i].chan, chnl[i].freq,
 					  chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
-					  " (NO_IBSS)" : "");
+					  " (NO_IBSS)" : "",
+					  chnl[i].flag & HOSTAPD_CHAN_RADAR ?
+					  " (DFS)" : "");
+
 			if (ret < 0 || ret >= end - pos)
 				return pos - buf;
 			pos += ret;
@@ -3232,9 +3355,9 @@
 	}
 
 	if (mask & WPA_BSS_MASK_AGE) {
-		struct os_time now;
+		struct os_reltime now;
 
-		os_get_time(&now);
+		os_get_reltime(&now);
 		ret = os_snprintf(pos, end - pos, "age=%d\n",
 				  (int) (now.sec - bss->last_update.sec));
 		if (ret < 0 || ret >= end - pos)
@@ -3295,7 +3418,8 @@
 				return 0;
 			pos += ret;
 		}
-		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+		    wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
 			ret = os_snprintf(pos, end - pos, "[P2P]");
 			if (ret < 0 || ret >= end - pos)
 				return 0;
@@ -3352,8 +3476,10 @@
 						  WFD_IE_VENDOR_TYPE);
 		if (wfd) {
 			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
-			if (ret < 0 || ret >= end - pos)
+			if (ret < 0 || ret >= end - pos) {
+				wpabuf_free(wfd);
 				return 0;
+			}
 			pos += ret;
 
 			pos += wpa_snprintf_hex(pos, end - pos,
@@ -3659,6 +3785,7 @@
 	unsigned int timeout = atoi(cmd);
 	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
 	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+	u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
 	char *pos;
 	unsigned int search_delay;
 
@@ -3675,6 +3802,14 @@
 		_dev_id = dev_id;
 	}
 
+	pos = os_strstr(cmd, "dev_type=");
+	if (pos) {
+		pos += 9;
+		if (wps_dev_type_str2bin(pos, dev_type) < 0)
+			return -1;
+		_dev_type = dev_type;
+	}
+
 	pos = os_strstr(cmd, "delay=");
 	if (pos) {
 		pos += 6;
@@ -3682,8 +3817,8 @@
 	} else
 		search_delay = wpas_p2p_search_delay(wpa_s);
 
-	return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
-			     search_delay);
+	return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
+			     _dev_id, search_delay);
 }
 
 
@@ -3703,12 +3838,12 @@
 	int go_intent = -1;
 	int freq = 0;
 	int pd;
-	int ht40;
+	int ht40, vht;
 
 	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
 	 * [persistent|persistent=<network id>]
 	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-	 * [ht40] */
+	 * [ht40] [vht] */
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -3736,7 +3871,9 @@
 	auth = os_strstr(pos, " auth") != NULL;
 	automatic = os_strstr(pos, " auto") != NULL;
 	pd = os_strstr(pos, " provdisc") != NULL;
-	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
 	pos2 = os_strstr(pos, " go_intent=");
 	if (pos2) {
@@ -3777,7 +3914,7 @@
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, automatic, join,
 				   auth, go_intent, freq, persistent_id, pd,
-				   ht40);
+				   ht40, vht);
 	if (new_pin == -2) {
 		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
 		return 25;
@@ -4141,7 +4278,7 @@
 	struct wpa_ssid *ssid;
 	u8 *_peer = NULL, peer[ETH_ALEN];
 	int freq = 0, pref_freq = 0;
-	int ht40;
+	int ht40, vht;
 
 	id = atoi(cmd);
 	pos = os_strstr(cmd, " peer=");
@@ -4175,9 +4312,12 @@
 			return -1;
 	}
 
-	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
-	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
+	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+			       pref_freq);
 }
 
 
@@ -4224,7 +4364,8 @@
 
 
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
-					 char *cmd, int freq, int ht40)
+					 char *cmd, int freq, int ht40,
+					 int vht)
 {
 	int id;
 	struct wpa_ssid *ssid;
@@ -4238,31 +4379,34 @@
 		return -1;
 	}
 
-	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
+					     NULL, 0);
 }
 
 
 static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
-	int freq = 0, ht40;
+	int freq = 0, ht40, vht;
 	char *pos;
 
 	pos = os_strstr(cmd, "freq=");
 	if (pos)
 		freq = atoi(pos + 5);
 
-	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+	vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
+	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+		vht;
 
 	if (os_strncmp(cmd, "persistent=", 11) == 0)
 		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
-						     ht40);
+						     ht40, vht);
 	if (os_strcmp(cmd, "persistent") == 0 ||
 	    os_strncmp(cmd, "persistent ", 11) == 0)
-		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
 	if (os_strncmp(cmd, "freq=", 5) == 0)
-		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
 	if (ht40)
-		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
 
 	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
 		   cmd);
@@ -4365,48 +4509,21 @@
 static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
 				  const char *param)
 {
-	struct wpa_freq_range *freq = NULL, *n;
-	unsigned int count = 0, i;
-	const char *pos, *pos2, *pos3;
+	unsigned int i;
 
 	if (wpa_s->global->p2p == NULL)
 		return -1;
 
-	/*
-	 * param includes comma separated frequency range.
-	 * For example: 2412-2432,2462,5000-6000
-	 */
-	pos = param;
-	while (pos && pos[0]) {
-		n = os_realloc_array(freq, count + 1,
-				     sizeof(struct wpa_freq_range));
-		if (n == NULL) {
-			os_free(freq);
-			return -1;
-		}
-		freq = n;
-		freq[count].min = atoi(pos);
-		pos2 = os_strchr(pos, '-');
-		pos3 = os_strchr(pos, ',');
-		if (pos2 && (!pos3 || pos2 < pos3)) {
-			pos2++;
-			freq[count].max = atoi(pos2);
-		} else
-			freq[count].max = freq[count].min;
-		pos = pos3;
-		if (pos)
-			pos++;
-		count++;
-	}
+	if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
+		return -1;
 
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
+		struct wpa_freq_range *freq;
+		freq = &wpa_s->global->p2p_disallow_freq.range[i];
 		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
-			   freq[i].min, freq[i].max);
+			   freq->min, freq->max);
 	}
 
-	os_free(wpa_s->global->p2p_disallow_freq);
-	wpa_s->global->p2p_disallow_freq = freq;
-	wpa_s->global->num_p2p_disallow_freq = count;
 	wpas_p2p_update_channel_list(wpa_s);
 	return 0;
 }
@@ -4602,6 +4719,16 @@
 		return 0;
 	}
 
+#ifdef CONFIG_WPS_NFC
+	if (os_strcmp(cmd, "nfc_tag") == 0)
+		return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
+#endif /* CONFIG_WPS_NFC */
+
+	if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
+		wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
+		return 0;
+	}
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
 		   cmd);
 
@@ -4689,7 +4816,68 @@
 #endif /* CONFIG_P2P */
 
 
+static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
+{
+	struct wpa_freq_range_list ranges;
+	int *freqs = NULL;
+	struct hostapd_hw_modes *mode;
+	u16 i;
+
+	if (wpa_s->hw.modes == NULL)
+		return NULL;
+
+	os_memset(&ranges, 0, sizeof(ranges));
+	if (freq_range_list_parse(&ranges, val) < 0)
+		return NULL;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		int j;
+
+		mode = &wpa_s->hw.modes[i];
+		for (j = 0; j < mode->num_channels; j++) {
+			unsigned int freq;
+
+			if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+
+			freq = mode->channels[j].freq;
+			if (!freq_range_list_includes(&ranges, freq))
+				continue;
+
+			int_array_add_unique(&freqs, freq);
+		}
+	}
+
+	os_free(ranges.range);
+	return freqs;
+}
+
+
 #ifdef CONFIG_INTERWORKING
+
+static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
+{
+	int auto_sel = 0;
+	int *freqs = NULL;
+
+	if (param) {
+		char *pos;
+
+		auto_sel = os_strstr(param, "auto") != NULL;
+
+		pos = os_strstr(param, "freq=");
+		if (pos) {
+			freqs = freq_range_to_channel_list(wpa_s, pos + 5);
+			if (freqs == NULL)
+				return -1;
+		}
+
+	}
+
+	return interworking_select(wpa_s, auto_sel, freqs);
+}
+
+
 static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
 {
 	u8 bssid[ETH_ALEN];
@@ -4813,9 +5001,8 @@
 	int used;
 	char *pos;
 	size_t resp_len, start, requested_len;
-
-	if (!wpa_s->last_gas_resp)
-		return -1;
+	struct wpabuf *resp;
+	int ret;
 
 	used = hwaddr_aton2(cmd, addr);
 	if (used < 0)
@@ -4826,11 +5013,18 @@
 		pos++;
 	dialog_token = atoi(pos);
 
-	if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
-	    dialog_token != wpa_s->last_gas_dialog_token)
+	if (wpa_s->last_gas_resp &&
+	    os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
+	    dialog_token == wpa_s->last_gas_dialog_token)
+		resp = wpa_s->last_gas_resp;
+	else if (wpa_s->prev_gas_resp &&
+		 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
+		 dialog_token == wpa_s->prev_gas_dialog_token)
+		resp = wpa_s->prev_gas_resp;
+	else
 		return -1;
 
-	resp_len = wpabuf_len(wpa_s->last_gas_resp);
+	resp_len = wpabuf_len(resp);
 	start = 0;
 	requested_len = resp_len;
 
@@ -4851,9 +5045,24 @@
 	if (requested_len * 2 + 1 > buflen)
 		return os_snprintf(buf, buflen, "FAIL-Too long response");
 
-	return wpa_snprintf_hex(buf, buflen,
-				wpabuf_head_u8(wpa_s->last_gas_resp) + start,
-				requested_len);
+	ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
+			       requested_len);
+
+	if (start + requested_len == resp_len) {
+		/*
+		 * Free memory by dropping the response after it has been
+		 * fetched.
+		 */
+		if (resp == wpa_s->prev_gas_resp) {
+			wpabuf_free(wpa_s->prev_gas_resp);
+			wpa_s->prev_gas_resp = NULL;
+		} else {
+			wpabuf_free(wpa_s->last_gas_resp);
+			wpa_s->last_gas_resp = NULL;
+		}
+	}
+
+	return ret;
 }
 #endif /* CONFIG_INTERWORKING */
 
@@ -5177,11 +5386,11 @@
 				p2p_set_country(p2p, country);
 			}
 		}
-		ret = sprintf(buf, "%s\n", "OK");
+		ret = os_snprintf(buf, buflen, "%s\n", "OK");
 	}
 	return ret;
 }
-#endif
+#endif /* ANDROID */
 
 
 static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
@@ -5192,21 +5401,30 @@
 	wpas_p2p_stop_find(wpa_s);
 	p2p_ctrl_flush(wpa_s);
 	wpas_p2p_group_remove(wpa_s, "*");
+	wpas_p2p_service_flush(wpa_s);
+	wpa_s->global->p2p_disabled = 0;
+	wpa_s->global->p2p_per_sta_psk = 0;
+	wpa_s->conf->num_sec_device_types = 0;
+	wpa_s->p2p_disable_ip_addr_req = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
 	wps_version_number = 0x20;
 	wps_testing_dummy_cred = 0;
+	wps_corrupt_pkhash = 0;
 #endif /* CONFIG_WPS_TESTING */
 #ifdef CONFIG_WPS
+	wpa_s->wps_fragment_size = 0;
 	wpas_wps_cancel(wpa_s);
 #endif /* CONFIG_WPS */
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
 
+#ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
 	extern unsigned int tdls_testing;
 	tdls_testing = 0;
 #endif /* CONFIG_TDLS_TESTING */
-#ifdef CONFIG_TDLS
 	wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
 	wpa_tdls_enable(wpa_s->wpa, 1);
 #endif /* CONFIG_TDLS */
@@ -5233,6 +5451,302 @@
 	wpa_s->extra_blacklist_count = 0;
 	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
 	wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+	wpa_config_flush_blobs(wpa_s->conf);
+	wpa_s->conf->auto_interworking = 0;
+	wpa_s->conf->okc = 0;
+	wpa_s->conf->pmf = 0;
+
+	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
+	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
+	wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
+	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+
+	radio_remove_works(wpa_s, NULL, 1);
+}
+
+
+static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
+				     char *buf, size_t buflen)
+{
+	struct wpa_radio_work *work;
+	char *pos, *end;
+	struct os_reltime now, diff;
+
+	pos = buf;
+	end = buf + buflen;
+
+	os_get_reltime(&now);
+
+	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+	{
+		int ret;
+
+		os_reltime_sub(&now, &work->time, &diff);
+		ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
+				  work->type, work->wpa_s->ifname, work->freq,
+				  work->started, diff.sec, diff.usec);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_radio_work *work = eloop_ctx;
+	struct wpa_external_work *ework = work->ctx;
+
+	wpa_dbg(work->wpa_s, MSG_DEBUG,
+		"Timing out external radio work %u (%s)",
+		ework->id, work->type);
+	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+	os_free(ework);
+	radio_work_done(work);
+}
+
+
+static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_external_work *ework = work->ctx;
+
+	if (deinit) {
+		if (work->started)
+			eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+					     work, NULL);
+
+		os_free(ework);
+		return;
+	}
+
+	wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+		ework->id, ework->type);
+	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+	if (!ework->timeout)
+		ework->timeout = 10;
+	eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
+			       work, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
+				    char *buf, size_t buflen)
+{
+	struct wpa_external_work *ework;
+	char *pos, *pos2;
+	size_t type_len;
+	int ret;
+	unsigned int freq = 0;
+
+	/* format: <name> [freq=<MHz>] [timeout=<seconds>] */
+
+	ework = os_zalloc(sizeof(*ework));
+	if (ework == NULL)
+		return -1;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos) {
+		type_len = pos - cmd;
+		pos++;
+
+		pos2 = os_strstr(pos, "freq=");
+		if (pos2)
+			freq = atoi(pos2 + 5);
+
+		pos2 = os_strstr(pos, "timeout=");
+		if (pos2)
+			ework->timeout = atoi(pos2 + 8);
+	} else {
+		type_len = os_strlen(cmd);
+	}
+	if (4 + type_len >= sizeof(ework->type))
+		type_len = sizeof(ework->type) - 4 - 1;
+	os_strlcpy(ework->type, "ext:", sizeof(ework->type));
+	os_memcpy(ework->type + 4, cmd, type_len);
+	ework->type[4 + type_len] = '\0';
+
+	wpa_s->ext_work_id++;
+	if (wpa_s->ext_work_id == 0)
+		wpa_s->ext_work_id++;
+	ework->id = wpa_s->ext_work_id;
+
+	if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
+			   ework) < 0) {
+		os_free(ework);
+		return -1;
+	}
+
+	ret = os_snprintf(buf, buflen, "%u", ework->id);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	struct wpa_radio_work *work;
+	unsigned int id = atoi(cmd);
+
+	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+	{
+		struct wpa_external_work *ework;
+
+		if (os_strncmp(work->type, "ext:", 4) != 0)
+			continue;
+		ework = work->ctx;
+		if (id && ework->id != id)
+			continue;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Completed external radio work %u (%s)",
+			ework->id, ework->type);
+		eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+		os_free(ework);
+		radio_work_done(work);
+		return 3; /* "OK\n" */
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
+				char *buf, size_t buflen)
+{
+	if (os_strcmp(cmd, "show") == 0)
+		return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
+	if (os_strncmp(cmd, "add ", 4) == 0)
+		return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
+	if (os_strncmp(cmd, "done ", 5) == 0)
+		return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
+	return -1;
+}
+
+
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_radio_work *work, *tmp;
+
+	if (!wpa_s || !wpa_s->radio)
+		return;
+
+	dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
+			      struct wpa_radio_work, list) {
+		struct wpa_external_work *ework;
+
+		if (os_strncmp(work->type, "ext:", 4) != 0)
+			continue;
+		ework = work->ctx;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Flushing %sexternal radio work %u (%s)",
+			work->started ? " started" : "", ework->id,
+			ework->type);
+		if (work->started)
+			eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+					     work, NULL);
+		os_free(ework);
+		radio_work_done(work);
+	}
+}
+
+
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
+static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val)
+{
+	int *freqs = NULL;
+
+	freqs = freq_range_to_channel_list(wpa_s, val);
+	if (freqs == NULL)
+		return -1;
+
+	os_free(wpa_s->manual_scan_freqs);
+	wpa_s->manual_scan_freqs = freqs;
+
+	return 0;
+}
+
+
+static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
+			   char *reply, int reply_size, int *reply_len)
+{
+	char *pos;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+		*reply_len = -1;
+		return;
+	}
+
+	wpa_s->manual_scan_passive = 0;
+	wpa_s->manual_scan_use_id = 0;
+	wpa_s->manual_scan_only_new = 0;
+
+	if (params) {
+		if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
+			wpa_s->scan_res_handler = scan_only_handler;
+
+		pos = os_strstr(params, "freq=");
+		if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) {
+			*reply_len = -1;
+			return;
+		}
+
+		pos = os_strstr(params, "passive=");
+		if (pos)
+			wpa_s->manual_scan_passive = !!atoi(pos + 8);
+
+		pos = os_strstr(params, "use_id=");
+		if (pos)
+			wpa_s->manual_scan_use_id = atoi(pos + 7);
+
+		pos = os_strstr(params, "only_new=1");
+		if (pos)
+			wpa_s->manual_scan_only_new = 1;
+	} else {
+		os_free(wpa_s->manual_scan_freqs);
+		wpa_s->manual_scan_freqs = NULL;
+		if (wpa_s->scan_res_handler == scan_only_handler)
+			wpa_s->scan_res_handler = NULL;
+	}
+
+	if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+	    ((wpa_s->wpa_state <= WPA_SCANNING) ||
+	     (wpa_s->wpa_state == WPA_COMPLETED))) {
+		wpa_s->normal_scans = 0;
+		wpa_s->scan_req = MANUAL_SCAN_REQ;
+		wpa_s->after_wps = 0;
+		wpa_s->known_wps_freq = 0;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		if (wpa_s->manual_scan_use_id) {
+			wpa_s->manual_scan_id++;
+			wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+				wpa_s->manual_scan_id);
+			*reply_len = os_snprintf(reply, reply_size, "%u\n",
+						 wpa_s->manual_scan_id);
+		}
+	} else if (wpa_s->sched_scanning) {
+		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_s->scan_req = MANUAL_SCAN_REQ;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		if (wpa_s->manual_scan_use_id) {
+			wpa_s->manual_scan_id++;
+			*reply_len = os_snprintf(reply, reply_size, "%u\n",
+						 wpa_s->manual_scan_id);
+			wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+				wpa_s->manual_scan_id);
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
+		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+	}
 }
 
 
@@ -5241,22 +5755,28 @@
 {
 	char *reply;
 	const int reply_size = 4096;
-	int ctrl_rsp = 0;
 	int reply_len;
 
 	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-	    os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
-	    os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
-	    os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
-	    os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
+	    os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+		if (wpa_debug_show_keys)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Control interface command '%s'", buf);
+		else
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Control interface command '%s [REMOVED]'",
+				os_strncmp(buf, WPA_CTRL_RSP,
+					   os_strlen(WPA_CTRL_RSP)) == 0 ?
+				WPA_CTRL_RSP : "SET_NETWORK");
+	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+		   os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
+		   os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
 		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
 				      (const u8 *) buf, os_strlen(buf));
 	} else {
 		int level = MSG_DEBUG;
 		if (os_strcmp(buf, "PING") == 0)
 			level = MSG_EXCESSIVE;
-		wpa_hexdump_ascii(level, "RX ctrl_iface",
-				  (const u8 *) buf, os_strlen(buf));
 		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
 	}
 
@@ -5380,9 +5900,6 @@
 	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
 		reply_len = wpas_ctrl_nfc_get_handover_sel(
 			wpa_s, buf + 21, reply, reply_size);
-	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
-		reply_len = wpas_ctrl_nfc_rx_handover_req(
-			wpa_s, buf + 20, reply, reply_size);
 	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
 		if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
 			reply_len = -1;
@@ -5468,7 +5985,7 @@
 		if (wpas_p2p_group_remove(wpa_s, buf + 17))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
-		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+		if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
 		if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -5550,9 +6067,11 @@
 			reply_len = -1;
 	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
 		interworking_stop_fetch_anqp(wpa_s);
-	} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
-		if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
-					NULL) < 0)
+	} else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
+		if (ctrl_interworking_select(wpa_s, NULL) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
+		if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
 			reply_len = -1;
 	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
 		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
@@ -5580,8 +6099,14 @@
 		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
 			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
 			reply_len = -1;
-		else
-			ctrl_rsp = 1;
+		else {
+			/*
+			 * Notify response from timeout to allow the control
+			 * interface response to be sent first.
+			 */
+			eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+					       wpa_s, NULL);
+		}
 	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
 		if (wpa_supplicant_reload_configuration(wpa_s))
 			reply_len = -1;
@@ -5609,34 +6134,10 @@
 		wpa_supplicant_cancel_scan(wpa_s);
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
-	} else if (os_strcmp(buf, "SCAN") == 0 ||
-		   os_strncmp(buf, "SCAN ", 5) == 0) {
-		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
-			reply_len = -1;
-		else {
-			if (os_strlen(buf) > 4 &&
-			    os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0)
-				wpa_s->scan_res_handler = scan_only_handler;
-			if (!wpa_s->sched_scanning && !wpa_s->scanning &&
-			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
-			     (wpa_s->wpa_state == WPA_COMPLETED))) {
-				wpa_s->normal_scans = 0;
-				wpa_s->scan_req = MANUAL_SCAN_REQ;
-				wpa_supplicant_req_scan(wpa_s, 0, 0);
-			} else if (wpa_s->sched_scanning) {
-				wpa_printf(MSG_DEBUG, "Stop ongoing "
-					   "sched_scan to allow requested "
-					   "full scan to proceed");
-				wpa_supplicant_cancel_sched_scan(wpa_s);
-				wpa_s->scan_req = MANUAL_SCAN_REQ;
-				wpa_supplicant_req_scan(wpa_s, 0, 0);
-			} else {
-				wpa_printf(MSG_DEBUG, "Ongoing scan action - "
-					   "reject new request");
-				reply_len = os_snprintf(reply, reply_size,
-							"FAIL-BUSY\n");
-			}
-		}
+	} 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) {
+		wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
 	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
 		reply_len = wpa_supplicant_ctrl_iface_scan_results(
 			wpa_s, reply, reply_size);
@@ -5711,6 +6212,9 @@
 	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
 		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+		if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+			reply_len = -1;
 #endif /* CONFIG_AP */
 	} else if (os_strcmp(buf, "SUSPEND") == 0) {
 		wpas_notify_suspend(wpa_s->global);
@@ -5760,7 +6264,7 @@
 	} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
 		reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
 						      reply_size);
-#endif
+#endif /* ANDROID */
 	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
 		pmksa_cache_clear_current(wpa_s->wpa);
 		eapol_sm_request_reauth(wpa_s->eapol);
@@ -5774,6 +6278,9 @@
 #endif /* CONFIG_WNM */
 	} else if (os_strcmp(buf, "FLUSH") == 0) {
 		wpa_supplicant_ctrl_iface_flush(wpa_s);
+	} else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
+		reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
+						 reply_size);
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -5784,9 +6291,6 @@
 		reply_len = 5;
 	}
 
-	if (ctrl_rsp)
-		eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
 	*resp_len = reply_len;
 	return reply;
 }
@@ -5993,10 +6497,8 @@
 {
 #ifdef CONFIG_P2P
 	static const char * cmd[] = {
-#ifdef ANDROID_P2P
 		"LIST_NETWORKS",
 		"SAVE_CONFIG",
-#endif
 		"P2P_FIND",
 		"P2P_STOP_FIND",
 		"P2P_LISTEN",
@@ -6011,12 +6513,12 @@
 		NULL
 	};
 	static const char * prefix[] = {
-#ifdef ANDROID_P2P
+#ifdef ANDROID
 		"DRIVER ",
+#endif /* ANDROID */
 		"GET_NETWORK ",
 		"REMOVE_NETWORK ",
 		"SET ",
-#endif
 		"P2P_FIND ",
 		"P2P_CONNECT ",
 		"P2P_LISTEN ",
@@ -6259,6 +6761,12 @@
 	} else if (os_strcmp(buf, "STATUS") == 0) {
 		reply_len = wpas_global_ctrl_iface_status(global, reply,
 							  reply_size);
+#ifdef CONFIG_MODULE_TESTS
+	} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
+		int wpas_module_tests(void);
+		if (wpas_module_tests() < 0)
+			reply_len = -1;
+#endif /* CONFIG_MODULE_TESTS */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index a329ef3..b0dec53 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -113,6 +113,8 @@
 void wpa_supplicant_global_ctrl_iface_deinit(
 	struct ctrl_iface_global_priv *priv);
 
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s);
+
 #else /* CONFIG_CTRL_IFACE */
 
 static inline struct ctrl_iface_priv *
@@ -148,6 +150,10 @@
 {
 }
 
+static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE */
 
 #endif /* CTRL_IFACE_H */
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index e35d2c3..d44313c 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -57,10 +57,17 @@
 };
 
 
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+					   const char *ifname, int sock,
 					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
-					   size_t len);
+					   size_t len,
+					   struct ctrl_iface_priv *priv,
+					   struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+				  struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+					 struct ctrl_iface_global_priv *priv);
 
 
 static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
@@ -68,6 +75,7 @@
 					    socklen_t fromlen)
 {
 	struct wpa_ctrl_dst *dst;
+	char addr_txt[200];
 
 	dst = os_zalloc(sizeof(*dst));
 	if (dst == NULL)
@@ -76,9 +84,10 @@
 	dst->addrlen = fromlen;
 	dst->debug_level = MSG_INFO;
 	dl_list_add(ctrl_dst, &dst->list);
-	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
-		    (u8 *) from->sun_path,
-		    fromlen - offsetof(struct sockaddr_un, sun_path));
+	printf_encode(addr_txt, sizeof(addr_txt),
+		      (u8 *) from->sun_path,
+		      fromlen - offsetof(struct sockaddr_un, sun_path));
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt);
 	return 0;
 }
 
@@ -94,10 +103,13 @@
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
 		    == 0) {
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-				    (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
+			char addr_txt[200];
+			printf_encode(addr_txt, sizeof(addr_txt),
+				      (u8 *) from->sun_path,
+				      fromlen -
+				      offsetof(struct sockaddr_un, sun_path));
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s",
+				   addr_txt);
 			dl_list_del(&dst->list);
 			os_free(dst);
 			return 0;
@@ -121,11 +133,13 @@
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
 		    == 0) {
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
-				    "level", (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
+			char addr_txt[200];
 			dst->debug_level = atoi(level);
+			printf_encode(addr_txt, sizeof(addr_txt),
+				      (u8 *) from->sun_path, fromlen -
+				      offsetof(struct sockaddr_un, sun_path));
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s",
+				   dst->debug_level, addr_txt);
 			return 0;
 		}
 	}
@@ -143,7 +157,7 @@
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
+	char *reply = NULL, *reply_buf = NULL;
 	size_t reply_len = 0;
 	int new_attached = 0;
 
@@ -177,21 +191,49 @@
 		else
 			reply_len = 2;
 	} else {
-		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
-							  &reply_len);
+		reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+							      &reply_len);
+		reply = reply_buf;
+	}
+
+	if (!reply && reply_len == 1) {
+		reply = "FAIL\n";
+		reply_len = 5;
+	} else if (!reply && reply_len == 2) {
+		reply = "OK\n";
+		reply_len = 3;
 	}
 
 	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} else if (reply_len == 1) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	} else if (reply_len == 2) {
-		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
-		       fromlen);
+		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+			   fromlen) < 0) {
+			int _errno = errno;
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"ctrl_iface sendto failed: %d - %s",
+				_errno, strerror(_errno));
+			if (_errno == ENOBUFS || _errno == EAGAIN) {
+				/*
+				 * The socket send buffer could be full. This
+				 * may happen if client programs are not
+				 * receiving their pending messages. Close and
+				 * reopen the socket as a workaround to avoid
+				 * getting stuck being unable to send any new
+				 * responses.
+				 */
+				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+				if (sock < 0) {
+					wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+				}
+			}
+			if (new_attached) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+				new_attached = 0;
+				wpa_supplicant_ctrl_iface_detach(
+					&priv->ctrl_dst, &from, fromlen);
+			}
+		}
 	}
+	os_free(reply_buf);
 
 	if (new_attached)
 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -262,26 +304,27 @@
 	if (global != 2 && wpa_s->global->ctrl_iface) {
 		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
 		if (!dl_list_empty(&priv->ctrl_dst)) {
-			wpa_supplicant_ctrl_iface_send(global ? NULL :
+			wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
 						       wpa_s->ifname,
 						       priv->sock,
 						       &priv->ctrl_dst,
-						       level, txt, len);
+						       level, txt, len, NULL,
+						       priv);
 		}
 	}
 
 	if (wpa_s->ctrl_iface == NULL)
 		return;
-	wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+	wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
 				       &wpa_s->ctrl_iface->ctrl_dst,
-				       level, txt, len);
+				       level, txt, len, wpa_s->ctrl_iface,
+				       NULL);
 }
 
 
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+				     struct ctrl_iface_priv *priv)
 {
-	struct ctrl_iface_priv *priv;
 	struct sockaddr_un addr;
 	char *fname = NULL;
 	gid_t gid = 0;
@@ -291,16 +334,6 @@
 	char *endp;
 	int flags;
 
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	dl_list_init(&priv->ctrl_dst);
-	priv->wpa_s = wpa_s;
-	priv->sock = -1;
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return priv;
-
 	buf = os_strdup(wpa_s->conf->ctrl_interface);
 	if (buf == NULL)
 		goto fail;
@@ -476,18 +509,61 @@
 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
 
 	os_free(buf);
-	return priv;
+	return 0;
 
 fail:
-	if (priv->sock >= 0)
+	if (priv->sock >= 0) {
 		close(priv->sock);
-	os_free(priv);
+		priv->sock = -1;
+	}
 	if (fname) {
 		unlink(fname);
 		os_free(fname);
 	}
 	os_free(buf);
-	return NULL;
+	return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->wpa_s = wpa_s;
+	priv->sock = -1;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+				  struct ctrl_iface_priv *priv)
+{
+	int res;
+
+	if (priv->sock <= 0)
+		return -1;
+
+	eloop_unregister_read_sock(priv->sock);
+	close(priv->sock);
+	priv->sock = -1;
+	res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+	if (res < 0)
+		return -1;
+	return priv->sock;
 }
 
 
@@ -517,6 +593,8 @@
 			os_free(fname);
 		}
 
+		if (priv->wpa_s->conf->ctrl_interface == NULL)
+			goto free_dst;
 		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
 		if (buf == NULL)
 			goto free_dst;
@@ -563,10 +641,13 @@
  *
  * Send a packet to all monitor programs attached to the control interface.
  */
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+					   const char *ifname, int sock,
 					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
-					   size_t len)
+					   size_t len,
+					   struct ctrl_iface_priv *priv,
+					   struct ctrl_iface_global_priv *gp)
 {
 	struct wpa_ctrl_dst *dst, *next;
 	char levelstr[10];
@@ -602,31 +683,58 @@
 	msg.msg_iov = io;
 	msg.msg_iovlen = idx;
 
-	idx = 0;
 	dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
-		if (level >= dst->debug_level) {
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
-				    (u8 *) dst->addr.sun_path, dst->addrlen -
-				    offsetof(struct sockaddr_un, sun_path));
-			msg.msg_name = (void *) &dst->addr;
-			msg.msg_namelen = dst->addrlen;
-			if (sendmsg(sock, &msg, MSG_DONTWAIT) < 0) {
-				int _errno = errno;
-				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
-					   "%d - %s",
-					   idx, errno, strerror(errno));
-				dst->errors++;
-				if (dst->errors > 1000 ||
-				    (_errno != ENOBUFS && dst->errors > 10) ||
-				    _errno == ENOENT) {
-					wpa_supplicant_ctrl_iface_detach(
-						ctrl_dst, &dst->addr,
-						dst->addrlen);
-				}
-			} else
-				dst->errors = 0;
+		int _errno;
+		char addr_txt[200];
+
+		if (level < dst->debug_level)
+			continue;
+
+		printf_encode(addr_txt, sizeof(addr_txt),
+			      (u8 *) dst->addr.sun_path, dst->addrlen -
+			      offsetof(struct sockaddr_un, sun_path));
+		msg.msg_name = (void *) &dst->addr;
+		msg.msg_namelen = dst->addrlen;
+		if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s",
+				   addr_txt);
+			dst->errors = 0;
+			continue;
 		}
-		idx++;
+
+		_errno = errno;
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
+			   addr_txt, errno, strerror(errno));
+		dst->errors++;
+
+		if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
+			wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages",
+				addr_txt);
+			wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+							 dst->addrlen);
+		}
+
+		if (_errno == ENOBUFS || _errno == EAGAIN) {
+			/*
+			 * The socket send buffer could be full. This may happen
+			 * if client programs are not receiving their pending
+			 * messages. Close and reopen the socket as a workaround
+			 * to avoid getting stuck being unable to send any new
+			 * responses.
+			 */
+			if (priv)
+				sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+			else if (gp)
+				sock = wpas_ctrl_iface_global_reinit(
+					wpa_s->global, gp);
+			else
+				break;
+			if (sock < 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"Failed to reinitialize ctrl_iface socket");
+				break;
+			}
+		}
 	}
 }
 
@@ -656,18 +764,30 @@
 			/* handle ATTACH signal of first monitor interface */
 			if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
 							      &from, fromlen)) {
-				sendto(priv->sock, "OK\n", 3, 0,
-				       (struct sockaddr *) &from, fromlen);
+				if (sendto(priv->sock, "OK\n", 3, 0,
+					   (struct sockaddr *) &from, fromlen) <
+				    0) {
+					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+						   strerror(errno));
+				}
 				/* OK to continue */
 				return;
 			} else {
-				sendto(priv->sock, "FAIL\n", 5, 0,
-				       (struct sockaddr *) &from, fromlen);
+				if (sendto(priv->sock, "FAIL\n", 5, 0,
+					   (struct sockaddr *) &from, fromlen) <
+				    0) {
+					wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+						   strerror(errno));
+				}
 			}
 		} else {
 			/* return FAIL for all other signals */
-			sendto(priv->sock, "FAIL\n", 5, 0,
-			       (struct sockaddr *) &from, fromlen);
+			if (sendto(priv->sock, "FAIL\n", 5, 0,
+				   (struct sockaddr *) &from, fromlen) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "ctrl_iface sendto failed: %s",
+					   strerror(errno));
+			}
 		}
 	}
 }
@@ -680,11 +800,11 @@
 {
 	struct wpa_global *global = eloop_ctx;
 	struct ctrl_iface_global_priv *priv = sock_ctx;
-	char buf[256];
+	char buf[4096];
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
+	char *reply = NULL, *reply_buf = NULL;
 	size_t reply_len;
 
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -709,41 +829,37 @@
 		else
 			reply_len = 2;
 	} else {
-		reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-								 &reply_len);
+		reply_buf = wpa_supplicant_global_ctrl_iface_process(
+			global, buf, &reply_len);
+		reply = reply_buf;
+	}
+
+	if (!reply && reply_len == 1) {
+		reply = "FAIL\n";
+		reply_len = 5;
+	} else if (!reply && reply_len == 2) {
+		reply = "OK\n";
+		reply_len = 3;
 	}
 
 	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} else if (reply_len == 1) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	} else if (reply_len == 2) {
-		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
+		if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+			   fromlen) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+				strerror(errno));
+		}
 	}
+	os_free(reply_buf);
 }
 
 
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+					    struct ctrl_iface_global_priv *priv)
 {
-	struct ctrl_iface_global_priv *priv;
 	struct sockaddr_un addr;
 	const char *ctrl = global->params.ctrl_interface;
 	int flags;
 
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	dl_list_init(&priv->ctrl_dst);
-	priv->global = global;
-	priv->sock = -1;
-
-	if (ctrl == NULL)
-		return priv;
-
 	wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
 
 #ifdef ANDROID
@@ -899,13 +1015,58 @@
 				 wpa_supplicant_global_ctrl_iface_receive,
 				 global, priv);
 
-	return priv;
+	return 0;
 
 fail:
-	if (priv->sock >= 0)
+	if (priv->sock >= 0) {
 		close(priv->sock);
-	os_free(priv);
-	return NULL;
+		priv->sock = -1;
+	}
+	return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->global = global;
+	priv->sock = -1;
+
+	if (global->params.ctrl_interface == NULL)
+		return priv;
+
+	if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+					 struct ctrl_iface_global_priv *priv)
+{
+	int res;
+
+	if (priv->sock <= 0)
+		return -1;
+
+	eloop_unregister_read_sock(priv->sock);
+	close(priv->sock);
+	priv->sock = -1;
+	res = wpas_global_ctrl_iface_open_sock(global, priv);
+	if (res < 0)
+		return -1;
+	return priv->sock;
 }
 
 
diff --git a/wpa_supplicant/dbus/Makefile b/wpa_supplicant/dbus/Makefile
index d64c65c..f355ebe 100644
--- a/wpa_supplicant/dbus/Makefile
+++ b/wpa_supplicant/dbus/Makefile
@@ -1,7 +1,7 @@
 all: libwpadbus.a
 
 clean:
-	rm -f *~ *.o *.d
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
 	rm -f libwpadbus.a
 
 install:
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ddd2c82..f40d421 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1362,7 +1362,7 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 
-	wpa_printf(MSG_INFO, "%s\n", __func__);
+	wpa_printf(MSG_DEBUG, "%s", __func__);
 
 	iface = wpa_s->global->dbus;
 	/* Do nothing if the control interface is not turned on */
@@ -2516,6 +2516,15 @@
 	  }
 	},
 #endif /* CONFIG_NO_CONFIG_BLOBS */
+	{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler)
+	  &wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+	  {
+		  { "pkcs11_engine_path", "s", ARG_IN },
+		  { "pkcs11_module_path", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
 #ifdef CONFIG_WPS
 	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
 	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
@@ -2736,6 +2745,37 @@
 	  }
 	},
 #endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_TDLS
+	{ "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  { "status", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
+	  {
+		  { "peer_address", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_TDLS */
 	{ NULL, NULL, NULL, { END_ARGS } }
 };
 
@@ -2812,6 +2852,14 @@
 	  wpas_dbus_getter_scan_interval,
 	  wpas_dbus_setter_scan_interval
 	},
+	{ "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_pkcs11_engine_path,
+	  NULL
+	},
+	{ "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_pkcs11_module_path,
+	  NULL
+	},
 #ifdef CONFIG_WPS
 	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
 	  wpas_dbus_getter_process_credentials,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 478d02f..5380b43 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -28,10 +28,6 @@
 #include "dbus_dict_helpers.h"
 #include "dbus_common_i.h"
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
 static const char *debug_strings[] = {
 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
 };
@@ -1236,6 +1232,23 @@
 }
 
 
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+					 DBusMessageIter *var,
+					 dbus_bool_t *allow,
+					 DBusMessage **reply)
+{
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Type must be a boolean");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Type value type. Boolean required");
+		return -1;
+	}
+	dbus_message_iter_get_basic(var, allow);
+	return 0;
+}
+
+
 /**
  * wpas_dbus_handler_scan - Request a wireless scan on an interface
  * @message: Pointer to incoming dbus message
@@ -1254,6 +1267,7 @@
 	char *key = NULL, *type = NULL;
 	struct wpa_driver_scan_params params;
 	size_t i;
+	dbus_bool_t allow_roam = 1;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -1284,6 +1298,12 @@
 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
 							&params, &reply) < 0)
 				goto out;
+		} else if (os_strcmp(key, "AllowRoam") == 0) {
+			if (wpas_dbus_get_scan_allow_roam(message,
+							  &variant_iter,
+							  &allow_roam,
+							  &reply) < 0)
+				goto out;
 		} else {
 			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
 				   "Unknown argument %s", key);
@@ -1332,6 +1352,9 @@
 		goto out;
 	}
 
+	if (!allow_roam)
+		wpa_s->scan_res_handler = scan_only_handler;
+
 out:
 	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
 		os_free((u8 *) params.ssids[i].ssid);
@@ -1970,6 +1993,227 @@
 }
 
 
+#ifdef CONFIG_TDLS
+
+static DBusMessage * get_peer_hwaddr_helper(DBusMessage *message,
+					    const char *func_name,
+					    u8 *peer_address)
+{
+	const char *peer_string;
+
+	if (!dbus_message_get_args(message, NULL,
+				   DBUS_TYPE_STRING, &peer_string,
+				   DBUS_TYPE_INVALID))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (hwaddr_aton(peer_string, peer_address)) {
+		wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
+			   func_name, peer_string);
+		return wpas_dbus_error_invalid_args(
+			message, "Invalid hardware address format");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_discover - Discover TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSDiscover" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS discovery");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_setup - Setup TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSSetup" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
+
+	wpa_tdls_remove(wpa_s->wpa, peer);
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_start(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS setup");
+	}
+
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_status - Return TDLS session status
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A string representing the state of the link to this TDLS peer
+ *
+ * Handler function for "TDLSStatus" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *reply;
+	const char *tdls_status;
+
+	reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (reply)
+		return reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
+
+	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_STRING,
+				 &tdls_status, DBUS_TYPE_INVALID);
+	return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSTeardown" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	u8 peer[ETH_ALEN];
+	DBusMessage *error_reply;
+	int ret;
+
+	error_reply = get_peer_hwaddr_helper(message, __func__, peer);
+	if (error_reply)
+		return error_reply;
+
+	wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_teardown_link(
+			wpa_s->wpa, peer,
+			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+	if (ret) {
+		return wpas_dbus_error_unknown_error(
+			message, "error performing TDLS teardown");
+	}
+
+	return NULL;
+}
+
+#endif /* CONFIG_TDLS */
+
+
+/**
+ * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing an error on failure or NULL on success
+ *
+ * Sets the PKCS #11 engine and module path.
+ */
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	char *value = NULL;
+	char *pkcs11_engine_path = NULL;
+	char *pkcs11_module_path = NULL;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &value);
+	if (value == NULL) {
+		return dbus_message_new_error(
+			message, DBUS_ERROR_INVALID_ARGS,
+			"Invalid pkcs11_engine_path argument");
+	}
+	/* Empty path defaults to NULL */
+	if (os_strlen(value))
+		pkcs11_engine_path = value;
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_get_basic(&iter, &value);
+	if (value == NULL) {
+		os_free(pkcs11_engine_path);
+		return dbus_message_new_error(
+			message, DBUS_ERROR_INVALID_ARGS,
+			"Invalid pkcs11_module_path argument");
+	}
+	/* Empty path defaults to NULL */
+	if (os_strlen(value))
+		pkcs11_module_path = value;
+
+	if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
+						   pkcs11_module_path))
+		return dbus_message_new_error(
+			message, DBUS_ERROR_FAILED,
+			"Reinit of the EAPOL state machine with the new PKCS "
+			"#11 engine and module path failed.");
+
+	wpa_dbus_mark_property_changed(
+		wpa_s->global->dbus, wpa_s->dbus_new_path,
+		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
+	wpa_dbus_mark_property_changed(
+		wpa_s->global->dbus, wpa_s->dbus_new_path,
+		WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
+
+	return NULL;
+}
+
+
 /**
  * wpas_dbus_getter_capabilities - Return interface capabilities
  * @iter: Pointer to incoming dbus message iter
@@ -2003,7 +2247,7 @@
 		const char *args[] = {"ccmp", "tkip", "none"};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Pairwise", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
@@ -2012,6 +2256,18 @@
 						      &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"))
@@ -2050,7 +2306,7 @@
 		};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Group", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
@@ -2059,6 +2315,18 @@
 						      &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"))
@@ -2107,7 +2375,7 @@
 		};
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "KeyMgmt", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
@@ -2187,7 +2455,7 @@
 		const char *args[] = { "rsn", "wpa" };
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Protocol", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
@@ -2222,7 +2490,7 @@
 		const char *args[] = { "open", "shared", "leap" };
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "AuthAlg", args,
-			    sizeof(args) / sizeof(char*)))
+			    ARRAY_SIZE(args)))
 			goto nomem;
 	} else {
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -2258,7 +2526,7 @@
 
 	/***** Scan */
 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
-					       sizeof(scans) / sizeof(char *)))
+					       ARRAY_SIZE(scans)))
 		goto nomem;
 
 	/***** Modes */
@@ -2986,6 +3254,76 @@
 
 
 /**
+ * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 engine path
+ *
+ * Getter for "PKCS11EnginePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *pkcs11_engine_path;
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
+			   "error occurred getting the PKCS #11 engine path.");
+		dbus_set_error_const(
+			error, DBUS_ERROR_FAILED,
+			"An error occured getting the PKCS #11 engine path.");
+		return FALSE;
+	}
+
+	if (wpa_s->conf->pkcs11_engine_path == NULL)
+		pkcs11_engine_path = "";
+	else
+		pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&pkcs11_engine_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 module path
+ *
+ * Getter for "PKCS11ModulePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *pkcs11_module_path;
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
+			   "error occurred getting the PKCS #11 module path.");
+		dbus_set_error_const(
+			error, DBUS_ERROR_FAILED,
+			"An error occured getting the PKCS #11 module path.");
+		return FALSE;
+	}
+
+	if (wpa_s->conf->pkcs11_module_path == NULL)
+		pkcs11_module_path = "";
+	else
+		pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&pkcs11_module_path, error);
+}
+
+
+/**
  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3283,7 +3621,7 @@
 {
 	DBusMessageIter iter_dict, variant_iter;
 	const char *group;
-	const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
+	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
 	const char *key_mgmt[7]; /* max 7 key managements may be supported */
 	int n;
 
@@ -3332,6 +3670,12 @@
 	case WPA_CIPHER_WEP104:
 		group = "wep104";
 		break;
+	case WPA_CIPHER_CCMP_256:
+		group = "ccmp-256";
+		break;
+	case WPA_CIPHER_GCMP_256:
+		group = "gcmp-256";
+		break;
 	default:
 		group = "";
 		break;
@@ -3348,6 +3692,10 @@
 		pairwise[n++] = "ccmp";
 	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
 		pairwise[n++] = "gcmp";
+	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
+		pairwise[n++] = "ccmp-256";
+	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
+		pairwise[n++] = "gcmp-256";
 
 	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
 					       pairwise, n))
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index fbc8358..c066944 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -122,6 +122,9 @@
 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
 					    struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
 					  struct wpa_supplicant *wpa_s);
 
@@ -218,6 +221,14 @@
 dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
 				      void *user_data);
 
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data);
+
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data);
+
 dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
 				   void *user_data);
 
@@ -278,6 +289,15 @@
 						 DBusError *error,
 						 void *user_data);
 
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 					   const char *arg);
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 6ec96df..2b83637 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,14 +346,14 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto inv_args;
 
-		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
-						  NULL)) {
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
+						  NULL, 0)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
 			goto out;
 		}
-	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
+	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
 		goto inv_args;
 
 out:
@@ -505,7 +505,7 @@
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, 0, join, authorize_only,
-				   go_intent, freq, -1, 0, 0);
+				   go_intent, freq, -1, 0, 0, 0);
 
 	if (new_pin >= 0) {
 		char npin[9];
@@ -631,8 +631,8 @@
 		if (ssid == NULL || ssid->disabled != 2)
 			goto err;
 
-		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
-		{
+		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
+		    0) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e565de9..7c4630e 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -25,10 +25,6 @@
 #include "dbus_old_handlers.h"
 #include "dbus_dict_helpers.h"
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
 /**
  * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
  * @message: Pointer to incoming dbus message this error refers to
@@ -539,7 +535,7 @@
 			const char *args[] = {"CCMP", "TKIP", "NONE"};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "pairwise", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -582,7 +578,7 @@
 			};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "group", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -632,7 +628,7 @@
 			};
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "key_mgmt", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -683,7 +679,7 @@
 			const char *args[] = { "RSN", "WPA" };
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "proto", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
@@ -720,7 +716,7 @@
 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "auth_alg", args,
-				    sizeof(args) / sizeof(char*)))
+				    ARRAY_SIZE(args)))
 				goto error;
 		}
 	} else {
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index aa6005f..6684782 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -20,63 +20,6 @@
 # used to fix build issues on such systems (krb5.h not found).
 #CFLAGS += -I/usr/include/kerberos
 
-# Example configuration for various cross-compilation platforms
-
-#### sveasoft (e.g., for Linksys WRT54G) ######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
-#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
-###############################################################################
-
-#### openwrt (e.g., for Linksys WRT54G) #######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
-#	-I../WRT54GS/release/src/include
-#LIBS = -lssl
-###############################################################################
-
-
-# Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for Agere driver
-#CONFIG_DRIVER_HERMES=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
-#CFLAGS += -I../../include/wireless
-
-# Driver interface for madwifi driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_MADWIFI=y
-# Set include directory to the madwifi source tree
-#CFLAGS += -I../../madwifi
-
-# Driver interface for ndiswrapper
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_NDISWRAPPER=y
-
-# Driver interface for Atmel driver
-CONFIG_DRIVER_ATMEL=y
-
-# Driver interface for old Broadcom driver
-# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
-# Linux wireless extensions and does not need (or even work) with the old
-# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
-#CONFIG_DRIVER_BROADCOM=y
-# Example path for wlioctl.h; change to match your configuration
-#CFLAGS += -I/opt/WRT54GS/release/src/include
-
-# Driver interface for Intel ipw2100/2200 driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_IPW=y
-
-# Driver interface for Ralink driver
-#CONFIG_DRIVER_RALINK=y
-
 # Driver interface for generic Linux wireless extensions
 # Note: WEXT is deprecated in the current Linux kernel version and no new
 # functionality is added to it. nl80211-based interface is the new
@@ -88,6 +31,19 @@
 # Driver interface for Linux drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -147,10 +103,9 @@
 CONFIG_EAP_TTLS=y
 
 # EAP-FAST
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
-# to add the needed functions.
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
 #CONFIG_EAP_FAST=y
 
 # EAP-GTC
@@ -307,7 +262,6 @@
 # Select event loop implementation
 # eloop = select() loop (default)
 # eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
 #CONFIG_ELOOP=eloop
 
 # Should we use poll instead of select? Select is used by default.
@@ -484,6 +438,10 @@
 # IEEE 802.11n (High Throughput) support (mainly for AP mode)
 #CONFIG_IEEE80211N=y
 
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
 # Wireless Network Management (IEEE Std 802.11v-2011)
 # Note: This is experimental and not complete implementation.
 #CONFIG_WNM=y
@@ -515,9 +473,14 @@
 # Enable TDLS support
 #CONFIG_TDLS=y
 
+# Wi-Fi Direct
+# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+#CONFIG_WIFI_DISPLAY=y
+
 # Autoscan
 # This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
 #
 # Enabling directly a module will enable autoscan support.
 # For exponential module:
diff --git a/wpa_supplicant/doc/docbook/Makefile b/wpa_supplicant/doc/docbook/Makefile
index aaeee2e..82f9de3 100644
--- a/wpa_supplicant/doc/docbook/Makefile
+++ b/wpa_supplicant/doc/docbook/Makefile
@@ -7,6 +7,7 @@
 FILES += wpa_priv
 FILES += wpa_supplicant.conf
 FILES += wpa_supplicant
+FILES += eapol_test
 
 man:
 	for i in $(FILES); do docbook2man $$i.sgml; done
@@ -20,7 +21,7 @@
 
 
 clean:
-	rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8
+	rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8 eapol_test.8
 	rm -f wpa_supplicant.conf.5
 	rm -f manpage.links manpage.refs
 	rm -f $(FILES:%=%.pdf)
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
new file mode 100644
index 0000000..fec174b
--- /dev/null
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -0,0 +1,205 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>eapol_test</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>eapol_test</refname>
+
+    <refpurpose>EAP peer and RADIUS client testing</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>eapol_test</command>
+      <arg>-nWS</arg>
+      <arg>-c<replaceable>config file</replaceable></arg>
+      <arg>-a<replaceable>server IP address</replaceable></arg>
+      <arg>-A<replaceable>client IP address</replaceable></arg>
+      <arg>-p<replaceable>UDP port</replaceable></arg>
+      <arg>-s<replaceable>shared secret</replaceable></arg>
+      <arg>-r<replaceable>re-authentications</replaceable></arg>
+      <arg>-t<replaceable>timeout</replaceable></arg>
+      <arg>-C<replaceable>Connect-Info</replaceable></arg>
+      <arg>-M<replaceable>MAC address</replaceable></arg>
+      <arg>-o<replaceable>file</replaceable></arg>
+      <arg>-N<replaceable>attr spec</replaceable></arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>eapol_test scard</command>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>eapol_test sim</command>
+      <arg>PIN</arg>
+      <arg>num triplets</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Overview</title>
+
+    <para>eapol_test is a program that links together the same EAP
+    peer implementation that wpa_supplicant is using and the RADIUS
+    authentication client code from hostapd. In addition, it has
+    minimal glue code to combine these two components in similar
+    ways to IEEE 802.1X/EAPOL Authenticator state machines. In other
+    words, it integrates IEEE 802.1X Authenticator (normally, an
+    access point) and IEEE 802.1X Supplicant (normally, a wireless
+    client) together to generate a single program that can be used to
+    test EAP methods without having to setup an access point and a
+    wireless client.</para>
+
+    <para>The main uses for eapol_test are in interoperability testing
+    of EAP methods against RADIUS servers and in development testing
+    for new EAP methods. It can be easily used to automate EAP testing
+    for interoperability and regression since the program can be run
+    from shell scripts without require additional test components apart
+    from a RADIUS server. For example, the automated EAP tests described
+    in eap_testing.txt are implemented with eapol_test. Similarly,
+    eapol_test could be used to implement an automated regression
+    test suite for a RADIUS authentication server.</para>
+
+
+    <para>As an example:</para>
+
+<blockquote><programlisting>
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+</programlisting></blockquote>
+
+    <para>tries to complete EAP authentication based on the network
+    configuration from test.conf against the RADIUS server running
+    on the local host. A re-authentication is triggered to test fast
+    re-authentication. The configuration file uses the same format for
+    network blocks as wpa_supplicant.</para>
+
+  </refsect1>
+  <refsect1>
+    <title>Command Arguments</title>
+    <variablelist>
+      <varlistentry>
+	<term>-c configuration file path</term>
+
+	<listitem><para>A configuration to use.  The configuration should
+	use the same format for network blocks as wpa_supplicant.
+	</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-a AS address</term>
+
+	<listitem><para>IP address of the authentication server.  The
+	default is '127.0.0.1'.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-A client address</term>
+
+	<listitem><para>IP address of the client.  The default is to
+	select an address automatically.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-p AS port</term>
+
+	<listitem><para>UDP port of the authentication server. The
+	default is '1812'.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-s AS secret</term>
+
+	<listitem><para>Shared secret with the authentication server.
+	The default is 'radius'.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-r count</term>
+
+	<listitem><para>Number of reauthentications.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-t timeout</term>
+
+	<listitem><para>Timeout in seconds. The default is 30.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-C info</term>
+
+	<listitem><para>RADIUS Connect-Info.  The default is
+	'CONNECT 11Mbps 802.11b'.</para></listitem>
+      </varlistentry>
+
+
+      <varlistentry>
+	<term>-M mac address</term>
+
+	<listitem><para>Client MAC address (Calling-Station-Id).  The
+	default is '02:00:00:00:00:01'.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-o file</term>
+
+	<listitem><para>Location to write out server certificate.
+	</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-N attr spec</term>
+
+	<listitem><para>Send arbitrary attribute specific by
+	attr_id:syntax:value, or attr_id alone.  attr_id should be the numeric
+	ID of the attribute, and syntax should be one of 's' (string),
+	'd' (integer), or 'x' (octet string). The value is the attribute value
+	to send.  When attr_id is given alone, NULL is used as the attribute
+	value.  Multiple attributes can be specified by using the option
+	several times.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-n</term>
+
+	<listitem><para>Indicates that no MPPE keys are expected.
+	</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-W</term>
+
+	<listitem><para>Wait for a control interface monitor before starting.
+	</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-S</term>
+
+	<listitem><para>Save configuration after authentication.
+	</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2014,
+    Jouni Malinen <email>j@w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index eb3a089..860b5a0 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-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 c080c07..142e1ab 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -15,10 +15,12 @@
     <cmdsynopsis>
       <command>wpa_cli</command>
       <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+      <arg>-g <replaceable>path to global ctrl_interface socket</replaceable></arg>
       <arg>-i <replaceable>ifname</replaceable></arg>
       <arg>-hvB</arg>
       <arg>-a <replaceable>action file</replaceable></arg>
       <arg>-P <replaceable>pid file</replaceable></arg>
+      <arg>-G <replaceable>ping interval</replaceable></arg>
       <arg><replaceable>command ...</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -111,6 +113,14 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-g control socket path</term>
+
+	<listitem><para>Connect to the global control socket at the
+	indicated path rather than an interface-specific control
+	socket.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>-i ifname</term>
 
         <listitem><para>Specify the interface that is being
@@ -161,6 +171,13 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-G ping interval</term>
+
+	<listitem><para>Set the interval (in seconds) at which
+	wpa_cli pings the supplicant.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>command</term>
 
 	<listitem><para>Run a command.  The available commands are
@@ -328,7 +345,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 0ab6419..f6ef8f1 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -74,7 +74,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 336c03b..3b4360b 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-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 eb907a8..9c114cc 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-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 aa20e57..182060d 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -12,7 +12,7 @@
   <refsynopsisdiv>
     <cmdsynopsis>
       <command>wpa_supplicant</command>
-      <arg>-BddfhKLqqtuvW</arg>
+      <arg>-BddfhKLqqsTtuvW</arg>
       <arg>-i<replaceable>ifname</replaceable></arg>
       <arg>-c<replaceable>config file</replaceable></arg>
       <arg>-D<replaceable>driver</replaceable></arg>
@@ -344,9 +344,20 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-e entropy file</term>
+	<listitem>
+	  <para>File for <command>wpa_supplicant</command> to use to
+	  maintain its internal entropy store in over restarts.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>-f output file</term>
 	<listitem>
-	  <para>Log output to specified file instead of stdout.</para>
+	  <para>Log output to specified file instead of stdout. (This
+	  is only available if <command>wpa_supplicant</command> was
+	  built with the <literal>CONFIG_DEBUG_FILE</literal>
+	  option.)</para>
 	</listitem>
       </varlistentry>
 
@@ -387,6 +398,22 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-o override driver</term>
+	<listitem>
+	  <para>Override the driver parameter for new
+	  interfaces.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-O override ctrl_interface</term>
+	<listitem>
+	  <para>Override the ctrl_interface parameter for new
+	  interfaces.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>-p</term>
 	<listitem>
 	  <para>Driver parameters. (Per interface)</para>
@@ -409,10 +436,40 @@
       </varlistentry>
 
       <varlistentry>
+	<term>-s</term>
+	<listitem>
+	  <para>Log output to syslog instead of stdout. (This is only
+	  available if <command>wpa_supplicant</command> was built
+	  with the <literal>CONFIG_DEBUG_SYSLOG</literal>
+	  option.)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-T</term>
+	<listitem>
+	  <para>Log output to Linux tracing in addition to any other
+	  destinations. (This is only available
+	  if <command>wpa_supplicant</command> was built with
+	  the <literal>CONFIG_DEBUG_LINUX_TRACING</literal>
+	  option.)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-t</term>
+	<listitem>
+	  <para>Include timestamp in debug messages.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>-u</term>
 	<listitem>
-	  <para>Enabled DBus control interface. If enabled, interface
-	  definitions may be omitted.</para>
+	  <para>Enable DBus control interface. If enabled, interface
+	  definitions may be omitted. (This is only available
+	  if <command>wpa_supplicant</command> was built with
+	  the <literal>CONFIG_DBUS</literal> option.)</para>0
 	</listitem>
       </varlistentry>
 
@@ -679,7 +736,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2012,
+    <para>wpa_supplicant is copyright (c) 2003-2014,
     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 5e7dbf7..0691b6c 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -117,11 +117,16 @@
 static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
+				  const u8 *seq, size_t seq_len,
+				  const u8 *key, size_t key_len)
 {
+	if (alg != WPA_ALG_NONE) {
+		if (key_idx >= 0 && key_idx <= 6)
+			wpa_s->keys_cleared &= ~BIT(key_idx);
+		else
+			wpa_s->keys_cleared = 0;
+	}
 	if (wpa_s->driver->set_key) {
-		wpa_s->keys_cleared = 0;
 		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
 					      alg, addr, key_idx, set_tx,
 					      seq, seq_len, key, key_len);
@@ -380,7 +385,7 @@
 	if (wpa_s->driver->if_add)
 		return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
 					     addr, bss_ctx, NULL, force_ifname,
-					     if_addr, bridge);
+					     if_addr, bridge, 0);
 	return -1;
 }
 
@@ -516,134 +521,6 @@
 	return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
 }
 
-static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
-				   unsigned int timeout, int type)
-{
-	if (!wpa_s->driver->p2p_find)
-		return -1;
-	return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
-}
-
-static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s->driver->p2p_stop_find)
-		return -1;
-	return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
-				     unsigned int timeout)
-{
-	if (!wpa_s->driver->p2p_listen)
-		return -1;
-	return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
-}
-
-static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
-				      const u8 *peer_addr, int wps_method,
-				      int go_intent,
-				      const u8 *own_interface_addr,
-				      unsigned int force_freq,
-				      int persistent_group)
-{
-	if (!wpa_s->driver->p2p_connect)
-		return -1;
-	return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
-					  wps_method, go_intent,
-					  own_interface_addr, force_freq,
-					  persistent_group);
-}
-
-static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
-					 const u8 *peer_addr)
-{
-	if (!wpa_s->driver->wps_success_cb)
-		return -1;
-	return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
-}
-
-static inline int
-wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s->driver->p2p_group_formation_failed)
-		return -1;
-	return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
-					 const struct p2p_params *params)
-{
-	if (!wpa_s->driver->p2p_set_params)
-		return -1;
-	return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
-}
-
-static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
-					    const u8 *peer_addr,
-					    u16 config_methods, int join)
-{
-	if (!wpa_s->driver->p2p_prov_disc_req)
-		return -1;
-	return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
-						config_methods, join);
-}
-
-static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
-					 const u8 *dst,
-					 const struct wpabuf *tlvs)
-{
-	if (!wpa_s->driver->p2p_sd_request)
-		return 0;
-	return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
-}
-
-static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
-						u64 req)
-{
-	if (!wpa_s->driver->p2p_sd_cancel_request)
-		return -1;
-	return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
-}
-
-static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
-					  int freq, const u8 *dst,
-					  u8 dialog_token,
-					  const struct wpabuf *resp_tlvs)
-{
-	if (!wpa_s->driver->p2p_sd_response)
-		return -1;
-	return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
-					      dialog_token, resp_tlvs);
-}
-
-static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s->driver->p2p_service_update)
-		return -1;
-	return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
-				     const u8 *addr)
-{
-	if (!wpa_s->driver->p2p_reject)
-		return -1;
-	return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
-}
-
-static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
-				     const u8 *peer, int role, const u8 *bssid,
-				     const u8 *ssid, size_t ssid_len,
-				     const u8 *go_dev_addr,
-				     int persistent_group)
-{
-	if (!wpa_s->driver->p2p_invite)
-		return -1;
-	return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
-					 ssid, ssid_len, go_dev_addr,
-					 persistent_group);
-}
-
 static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
 					 const u8 *dst, u8 action_code,
 					 u8 dialog_token, u16 status_code,
@@ -673,7 +550,7 @@
 		return -1;
 	return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
 }
-#endif
+#endif /* ANDROID */
 
 static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
 					  const u8 *kek, const u8 *kck,
@@ -693,11 +570,11 @@
 }
 
 static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
-					 unsigned int freq)
+					 struct csa_settings *settings)
 {
 	if (!wpa_s->driver->switch_channel)
 		return -1;
-	return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+	return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
 }
 
 static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
@@ -710,4 +587,21 @@
 				       buf_len);
 }
 
+static inline int wpa_drv_status(struct wpa_supplicant *wpa_s,
+				 char *buf, size_t buflen)
+{
+	if (!wpa_s->driver->status)
+		return -1;
+	return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
+}
+
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+				      const u8 *qos_map_set, u8 qos_map_set_len)
+{
+	if (!wpa_s->driver->set_qos_map)
+		return -1;
+	return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+					  qos_map_set_len);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index dad2765..ac0ab0b 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,11 +27,9 @@
 #include "common/wpa_ctrl.h"
 #include "ctrl_iface.h"
 #include "pcsc_funcs.h"
+#include "wpas_glue.h"
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
 struct wpa_driver_ops *wpa_drivers[] = { NULL };
 
 
@@ -367,10 +365,11 @@
 }
 
 
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
+			void *ctx)
 {
 	struct eapol_test_data *e = ctx;
-	printf("eapol_sm_cb: success=%d\n", success);
+	printf("eapol_sm_cb: result=%d\n", result);
 	e->eapol_test_num_reauths--;
 	if (e->eapol_test_num_reauths < 0)
 		eloop_terminate();
@@ -395,6 +394,54 @@
 }
 
 
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+					const char *default_txt)
+{
+	struct eapol_test_data *e = ctx;
+	struct wpa_supplicant *wpa_s = e->wpa_s;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
+	char *buf;
+	size_t buflen;
+	int len;
+
+	if (ssid == NULL)
+		return;
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen,
+			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (len < 0 || (size_t) len >= buflen) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+	os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
 			       const char *cert_hash,
 			       const struct wpabuf *cert)
@@ -484,6 +531,7 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->eap_param_needed = eapol_test_eap_param_needed;
 	ctx->cert_cb = eapol_test_cert_cb;
 	ctx->cert_in_cb = 1;
 	ctx->set_anon_id = eapol_test_set_anon_id;
@@ -501,6 +549,7 @@
 	eapol_conf.required_keys = 0;
 	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
 
@@ -892,7 +941,7 @@
 	unsigned char aka_ik[IK_LEN];
 	unsigned char aka_ck[CK_LEN];
 
-	scard = scard_init(SCARD_TRY_BOTH, NULL);
+	scard = scard_init(NULL);
 	if (scard == NULL)
 		return -1;
 	if (scard_set_pin(scard, "1234")) {
@@ -992,7 +1041,7 @@
 		wpa_debug_level = 99;
 	}
 
-	scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
+	scard = scard_init(NULL);
 	if (scard == NULL) {
 		printf("Failed to open smartcard connection\n");
 		return -1;
@@ -1094,6 +1143,7 @@
 
 int main(int argc, char *argv[])
 {
+	struct wpa_global global;
 	struct wpa_supplicant wpa_s;
 	int c, ret = 1, wait_for_monitor = 0, save_config = 0;
 	char *as_addr = "127.0.0.1";
@@ -1230,8 +1280,12 @@
 		return -1;
 	}
 
+	os_memset(&global, 0, sizeof(global));
 	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	wpa_s.global = &global;
 	eapol_test.wpa_s = &wpa_s;
+	dl_list_init(&wpa_s.bss);
+	dl_list_init(&wpa_s.bss_id);
 	wpa_s.conf = wpa_config_read(conf, NULL);
 	if (wpa_s.conf == NULL) {
 		printf("Failed to parse configuration file '%s'.\n", conf);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 9de8d7f..c5e65ef 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -46,19 +46,19 @@
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan);
+					      int new_scan, int own_request);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
 static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
 			      struct wpa_ssid *ssid)
 {
-	struct os_time now;
+	struct os_reltime now;
 
 	if (ssid == NULL || ssid->disabled_until.sec == 0)
 		return 0;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	if (ssid->disabled_until.sec > now.sec)
 		return ssid->disabled_until.sec - now.sec;
 
@@ -68,9 +68,25 @@
 }
 
 
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+	struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_bss *bss = NULL;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid->ssid_len > 0)
+		bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+	if (!bss)
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+	return bss;
+}
+
+
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_ssid *ssid, *old_ssid;
+	struct wpa_bss *bss;
 	int res;
 
 	if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
@@ -119,6 +135,18 @@
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
 	old_ssid = wpa_s->current_ssid;
 	wpa_s->current_ssid = ssid;
+
+	bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+	if (!bss) {
+		wpa_supplicant_update_scan_results(wpa_s);
+
+		/* Get the BSS from the new scan results */
+		bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+	}
+
+	if (bss)
+		wpa_s->current_bss = bss;
+
 	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
 	wpa_supplicant_initiate_eapol(wpa_s);
 	if (old_ssid != wpa_s->current_ssid)
@@ -160,9 +188,6 @@
 		return;
 
 	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-#ifdef ANDROID
-	wpa_s->conf->ap_scan = DEFAULT_AP_SCAN;
-#endif
 	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 	os_memset(wpa_s->bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
@@ -278,7 +303,8 @@
 #ifdef PCSC_FUNCS
 	int aka = 0, sim = 0;
 
-	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL ||
+	    wpa_s->conf->external_sim)
 		return 0;
 
 	if (ssid->eap.eap_methods == NULL) {
@@ -316,8 +342,7 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
 		"(sim=%d aka=%d) - initialize PCSC", sim, aka);
 
-	wpa_s->scard = scard_init((!sim && aka) ? SCARD_USIM_ONLY :
-				  SCARD_TRY_BOTH, NULL);
+	wpa_s->scard = scard_init(NULL);
 	if (wpa_s->scard == NULL) {
 		wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
 			"(pcsc-lite)");
@@ -718,10 +743,13 @@
 	rsn_ie_len = ie ? ie[1] : 0;
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
+		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s",
 		i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
 		wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
-		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
+		(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+		 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
+		" p2p" : "");
 
 	e = wpa_blacklist_get(wpa_s, bss->bssid);
 	if (e) {
@@ -858,6 +886,39 @@
 		}
 
 #ifdef CONFIG_P2P
+		if (ssid->p2p_group &&
+		    !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+		    !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P IE seen");
+			continue;
+		}
+
+		if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+			struct wpabuf *p2p_ie;
+			u8 dev_addr[ETH_ALEN];
+
+			ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+			if (ie == NULL) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P element");
+				continue;
+			}
+			p2p_ie = wpa_bss_get_vendor_ie_multi(
+				bss, P2P_IE_VENDOR_TYPE);
+			if (p2p_ie == NULL) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - could not fetch P2P element");
+				continue;
+			}
+
+			if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
+			    || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
+					 ETH_ALEN) != 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no matching GO P2P Device Address in P2P element");
+				wpabuf_free(p2p_ie);
+				continue;
+			}
+			wpabuf_free(p2p_ie);
+		}
+
 		/*
 		 * TODO: skip the AP if its P2P IE has Group Formation
 		 * bit set in the P2P Group Capability Bitmap and we
@@ -945,9 +1006,6 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
 			"since there are no enabled networks");
 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-#ifdef CONFIG_P2P
-		wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
 		return;
 	}
 
@@ -1148,7 +1206,8 @@
 					      union wpa_event_data *data,
 					      int own_request)
 {
-	struct wpa_scan_results *scan_res;
+	struct wpa_scan_results *scan_res = NULL;
+	int ret = 0;
 	int ap = 0;
 #ifndef CONFIG_NO_RANDOM_POOL
 	size_t i, num;
@@ -1161,23 +1220,6 @@
 
 	wpa_supplicant_notify_scanning(wpa_s, 0);
 
-#ifdef CONFIG_P2P
-	if (own_request && wpa_s->global->p2p_cb_on_scan_complete &&
-	    !wpa_s->global->p2p_disabled &&
-	    wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
-	    !wpa_s->scan_res_handler) {
-		wpa_s->global->p2p_cb_on_scan_complete = 0;
-		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
-				"stopped scan processing");
-			wpa_s->sta_scan_pending = 1;
-			wpa_supplicant_req_scan(wpa_s, 5, 0);
-			return -1;
-		}
-	}
-	wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
-
 	scan_res = wpa_supplicant_get_scan_results(wpa_s,
 						   data ? &data->scan_info :
 						   NULL, 1);
@@ -1190,7 +1232,8 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
 			"scanning again");
 		wpa_supplicant_req_new_scan(wpa_s, 1, 0);
-		return -1;
+		ret = -1;
+		goto scan_work_done;
 	}
 
 #ifndef CONFIG_NO_RANDOM_POOL
@@ -1209,16 +1252,16 @@
 	}
 #endif /* CONFIG_NO_RANDOM_POOL */
 
-	if (own_request && wpa_s->scan_res_handler) {
+	if (own_request && wpa_s->scan_res_handler &&
+	    (wpa_s->own_scan_running || !wpa_s->external_scan_running)) {
 		void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
 					 struct wpa_scan_results *scan_res);
 
 		scan_res_handler = wpa_s->scan_res_handler;
 		wpa_s->scan_res_handler = NULL;
 		scan_res_handler(wpa_s, scan_res);
-
-		wpa_scan_results_free(scan_res);
-		return -2;
+		ret = -2;
+		goto scan_work_done;
 	}
 
 	if (ap) {
@@ -1227,53 +1270,72 @@
 		if (wpa_s->ap_iface->scan_cb)
 			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
 #endif /* CONFIG_AP */
-		wpa_scan_results_free(scan_res);
-		return 0;
+		goto scan_work_done;
 	}
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
-	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
+		wpa_s->own_scan_running, wpa_s->external_scan_running);
+	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+	    wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
+			     wpa_s->manual_scan_id);
+		wpa_s->manual_scan_use_id = 0;
+	} else {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	}
 	wpas_notify_scan_results(wpa_s);
 
 	wpas_notify_scan_done(wpa_s, 1);
 
-	if (sme_proc_obss_scan(wpa_s) > 0) {
+	if (!wpa_s->own_scan_running && wpa_s->external_scan_running) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
 		wpa_scan_results_free(scan_res);
 		return 0;
 	}
 
-	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	if (sme_proc_obss_scan(wpa_s) > 0)
+		goto scan_work_done;
 
-	if (autoscan_notify_scan(wpa_s, scan_res)) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
+		goto scan_work_done;
+
+	if (autoscan_notify_scan(wpa_s, scan_res))
+		goto scan_work_done;
 
 	if (wpa_s->disconnected) {
 		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-		wpa_scan_results_free(scan_res);
-		return 0;
+		goto scan_work_done;
 	}
 
 	if (!wpas_driver_bss_selection(wpa_s) &&
-	    bgscan_notify_scan(wpa_s, scan_res) == 1) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	    bgscan_notify_scan(wpa_s, scan_res) == 1)
+		goto scan_work_done;
 
 	wpas_wps_update_ap_info(wpa_s, scan_res);
 
 	wpa_scan_results_free(scan_res);
 
-	return wpas_select_network_from_last_scan(wpa_s, 1);
+	if (wpa_s->scan_work) {
+		struct wpa_radio_work *work = wpa_s->scan_work;
+		wpa_s->scan_work = NULL;
+		radio_work_done(work);
+	}
+
+	return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
+
+scan_work_done:
+	wpa_scan_results_free(scan_res);
+	if (wpa_s->scan_work) {
+		struct wpa_radio_work *work = wpa_s->scan_work;
+		wpa_s->scan_work = NULL;
+		radio_work_done(work);
+	}
+	return ret;
 }
 
 
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan)
+					      int new_scan, int own_request)
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
@@ -1308,17 +1370,24 @@
 			wpa_supplicant_associate(wpa_s, NULL, ssid);
 			if (new_scan)
 				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
-		} else {
+		} else if (own_request) {
+			/*
+			 * No SSID found. If SCAN results are as a result of
+			 * own scan request and not due to a scan request on
+			 * another shared interface, try another scan.
+			 */
 			int timeout_sec = wpa_s->scan_interval;
 			int timeout_usec = 0;
 #ifdef CONFIG_P2P
 			if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
 				return 0;
 
-			if (wpa_s->p2p_in_provisioning) {
+			if (wpa_s->p2p_in_provisioning ||
+			    wpa_s->show_group_started) {
 				/*
 				 * Use shorter wait during P2P Provisioning
-				 * state to speed up group formation.
+				 * state and during P2P join-a-group operation
+				 * to speed up group formation.
 				 */
 				timeout_sec = 0;
 				timeout_usec = 250000;
@@ -1340,6 +1409,16 @@
 				return 1;
 			}
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_WPS
+			if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing");
+				timeout_sec = 0;
+				timeout_usec = 500000;
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+				return 0;
+			}
+#endif /* CONFIG_WPS */
 			if (wpa_supplicant_req_sched_scan(wpa_s))
 				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
 							    timeout_usec);
@@ -1352,7 +1431,6 @@
 static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 					      union wpa_event_data *data)
 {
-	const char *rn, *rn2;
 	struct wpa_supplicant *ifs;
 
 	if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
@@ -1367,25 +1445,12 @@
 	}
 
 	/*
-	 * Check other interfaces to see if they have the same radio-name. If
+	 * Check other interfaces to see if they share the same radio. If
 	 * so, they get updated with this same scan info.
 	 */
-	if (!wpa_s->driver->get_radio_name)
-		return;
-
-	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
-		return;
-
-	wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
-		"sharing same radio (%s) in event_scan_results", rn);
-
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
-			continue;
-
-		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
-		if (rn2 && os_strcmp(rn, rn2) == 0) {
+	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+			 radio_list) {
+		if (ifs != wpa_s) {
 			wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
 				   "sibling", ifs->ifname);
 			_wpa_supplicant_event_scan_results(ifs, data, 0);
@@ -1401,18 +1466,18 @@
 #ifdef CONFIG_NO_SCAN_PROCESSING
 	return -1;
 #else /* CONFIG_NO_SCAN_PROCESSING */
-	struct os_time now;
+	struct os_reltime now;
 
 	if (wpa_s->last_scan_res_used <= 0)
 		return -1;
 
-	os_get_time(&now);
-	if (now.sec - wpa_s->last_scan.sec > 5) {
+	os_get_reltime(&now);
+	if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
 		wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
 		return -1;
 	}
 
-	return wpas_select_network_from_last_scan(wpa_s, 0);
+	return wpas_select_network_from_last_scan(wpa_s, 0, 1);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
@@ -1496,6 +1561,43 @@
 }
 
 
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+			    size_t len)
+{
+	int res;
+
+	wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+	res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+	}
+
+	return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return;
+
+	if (elems.qos_map_set) {
+		wpas_qos_map_set(wpa_s, elems.qos_map_set,
+				 elems.qos_map_set_len);
+	}
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 					  union wpa_event_data *data)
 {
@@ -1520,6 +1622,10 @@
 		wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
 				       data->assoc_info.resp_ies_len);
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+						data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
 	}
 	if (data->assoc_info.beacon_ies)
 		wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1688,21 +1794,6 @@
 }
 
 
-static struct wpa_bss * wpa_supplicant_get_new_bss(
-	struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct wpa_bss *bss = NULL;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	if (ssid->ssid_len > 0)
-		bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
-	if (!bss)
-		bss = wpa_bss_get_bssid(wpa_s, bssid);
-
-	return bss;
-}
-
-
 static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
 {
 	const u8 *bss_wpa = NULL, *bss_rsn = NULL;
@@ -1772,20 +1863,6 @@
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 			return;
 		}
-		if (wpa_s->current_ssid) {
-			struct wpa_bss *bss = NULL;
-
-			bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
-			if (!bss) {
-				wpa_supplicant_update_scan_results(wpa_s);
-
-				/* Get the BSS from the new scan results */
-				bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
-			}
-
-			if (bss)
-				wpa_s->current_bss = bss;
-		}
 
 #ifdef ANDROID
 		if (wpa_s->conf->ap_scan == 1) {
@@ -1887,9 +1964,9 @@
 	wpa_s->last_eapol_matches_bssid = 0;
 
 	if (wpa_s->pending_eapol_rx) {
-		struct os_time now, age;
-		os_get_time(&now);
-		os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+		struct os_reltime now, age;
+		os_get_reltime(&now);
+		os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
 		if (age.sec == 0 && age.usec < 100000 &&
 		    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
 		    0) {
@@ -2051,11 +2128,7 @@
 			fast_reconnect_ssid = wpa_s->current_ssid;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
-#ifdef ANDROID
-			wpa_supplicant_req_scan(wpa_s, 0, 500000);
-#else
 			wpa_supplicant_req_scan(wpa_s, 0, 100000);
-#endif
 		else
 			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
 				"immediate scan");
@@ -2079,7 +2152,6 @@
 	wpas_notify_disconnect_reason(wpa_s);
 	if (wpa_supplicant_dynamic_keys(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
-		wpa_s->keys_cleared = 0;
 		wpa_clear_keys(wpa_s, wpa_s->bssid);
 	}
 	last_ssid = wpa_s->current_ssid;
@@ -2123,13 +2195,13 @@
 					 union wpa_event_data *data)
 {
 	int pairwise;
-	struct os_time t;
+	struct os_reltime t;
 
 	wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
 	pairwise = (data && data->michael_mic_failure.unicast);
-	os_get_time(&t);
-	if ((wpa_s->last_michael_mic_error &&
-	     t.sec - wpa_s->last_michael_mic_error <= 60) ||
+	os_get_reltime(&t);
+	if ((wpa_s->last_michael_mic_error.sec &&
+	     !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) ||
 	    wpa_s->pending_mic_error_report) {
 		if (wpa_s->pending_mic_error_report) {
 			/*
@@ -2207,7 +2279,7 @@
 		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 	}
-	wpa_s->last_michael_mic_error = t.sec;
+	wpa_s->last_michael_mic_error = t;
 	wpa_s->mic_errors_seen++;
 }
 
@@ -2242,7 +2314,6 @@
 			wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
 				"driver after interface was added");
 		}
-		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 		break;
 	case EVENT_INTERFACE_REMOVED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
@@ -2478,10 +2549,11 @@
 
 	wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
 
-	if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
-	    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-	      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
-	     eapol_sm_failed(wpa_s->eapol)))
+	if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+	      ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+		(wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+	       eapol_sm_failed(wpa_s->eapol))) &&
+	     !wpa_s->eap_expected_failure))
 		wpas_auth_failed(wpa_s);
 
 #ifdef CONFIG_P2P
@@ -2591,6 +2663,173 @@
 }
 
 
+static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_supplicant *ifs;
+
+	if (wpa_s->drv_priv == NULL)
+		return; /* Ignore event during drv initialization */
+
+	free_hw_features(wpa_s);
+	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+		wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+	wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+
+	/*
+	 * Check other interfaces to see if they share the same radio. If
+	 * so, they get updated with this same hw mode info.
+	 */
+	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+			 radio_list) {
+		if (ifs != wpa_s) {
+			wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
+				   ifs->ifname);
+			free_hw_features(ifs);
+			ifs->hw.modes = wpa_drv_get_hw_feature_data(
+				ifs, &ifs->hw.num_modes, &ifs->hw.flags);
+		}
+	}
+}
+
+
+static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
+				      const struct ieee80211_mgmt *mgmt,
+				      size_t len, int freq)
+{
+	const u8 *payload;
+	size_t plen;
+	u8 category;
+
+	if (len < IEEE80211_HDRLEN + 2)
+		return;
+
+	payload = &mgmt->u.action.category;
+	category = *payload++;
+	plen = (((const u8 *) mgmt) + len) - payload;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+		" Category=%u DataLen=%d freq=%d MHz",
+		MAC2STR(mgmt->sa), category, (int) plen, freq);
+
+#ifdef CONFIG_IEEE80211R
+	if (category == WLAN_ACTION_FT) {
+		ft_rx_action(wpa_s, payload, plen);
+		return;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+	if (category == WLAN_ACTION_SA_QUERY) {
+		sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
+		return;
+	}
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WNM
+	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
+		ieee802_11_rx_wnm_action(wpa_s, mgmt, len);
+		return;
+	}
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_GAS
+	if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+	     mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+	    gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid,
+			 mgmt->u.action.category,
+			 payload, plen, freq) == 0)
+		return;
+#endif /* CONFIG_GAS */
+
+#ifdef CONFIG_TDLS
+	if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
+	    payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TDLS: Received Discovery Response from " MACSTR,
+			MAC2STR(mgmt->sa));
+		return;
+	}
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_INTERWORKING
+	if (category == WLAN_ACTION_QOS && plen >= 1 &&
+	    payload[0] == QOS_QOS_MAP_CONFIG) {
+		const u8 *pos = payload + 1;
+		size_t qlen = plen - 1;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+			MACSTR, MAC2STR(mgmt->sa));
+		if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 &&
+		    qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET &&
+		    pos[1] <= qlen - 2 && pos[1] >= 16)
+			wpas_qos_map_set(wpa_s, pos + 2, pos[1]);
+		return;
+	}
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_P2P
+	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+			   category, payload, plen, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
+					     union wpa_event_data *event)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *ifs;
+#endif /* CONFIG_P2P */
+	struct wpa_freq_range_list *list;
+	char *str = NULL;
+
+	list = &event->freq_range;
+
+	if (list->num)
+		str = freq_range_list_str(list);
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s",
+		str ? str : "");
+
+#ifdef CONFIG_P2P
+	if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) {
+		wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range",
+			__func__);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event");
+		wpas_p2p_update_channel_list(wpa_s);
+	}
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		int freq;
+		if (!ifs->current_ssid ||
+		    !ifs->current_ssid->p2p_group ||
+		    (ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
+		     ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
+			continue;
+
+		freq = ifs->current_ssid->frequency;
+		if (!freq_range_list_includes(list, freq)) {
+			wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range",
+				freq);
+			continue;
+		}
+
+		wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz",
+			freq);
+		/* TODO: Consider using CSA or removing the group within
+		 * wpa_supplicant */
+		wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
+	}
+#endif /* CONFIG_P2P */
+
+	os_free(str);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -2644,11 +2883,44 @@
 		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
 		break;
 #ifndef CONFIG_NO_SCAN_PROCESSING
+	case EVENT_SCAN_STARTED:
+		os_get_reltime(&wpa_s->scan_start_time);
+		if (wpa_s->own_scan_requested) {
+			struct os_reltime diff;
+
+			os_reltime_sub(&wpa_s->scan_start_time,
+				       &wpa_s->scan_trigger_time, &diff);
+			wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds",
+				diff.sec, diff.usec);
+			wpa_s->own_scan_requested = 0;
+			wpa_s->own_scan_running = 1;
+			if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+			    wpa_s->manual_scan_use_id) {
+				wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u",
+					wpa_s->manual_scan_id);
+			} else {
+				wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+			}
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
+			wpa_s->external_scan_running = 1;
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+		}
+		break;
 	case EVENT_SCAN_RESULTS:
+		if (os_reltime_initialized(&wpa_s->scan_start_time)) {
+			struct os_reltime now, diff;
+			os_get_reltime(&now);
+			os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
+			wpa_s->scan_start_time.sec = 0;
+			wpa_s->scan_start_time.usec = 0;
+			wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
+				diff.sec, diff.usec);
+		}
 		wpa_supplicant_event_scan_results(wpa_s, data);
-		if (wpa_s->wpa_state != WPA_AUTHENTICATING &&
-		    wpa_s->wpa_state != WPA_ASSOCIATING)
-			wpas_p2p_continue_after_scan(wpa_s);
+		wpa_s->own_scan_running = 0;
+		wpa_s->external_scan_running = 0;
+		radio_work_check_next(wpa_s);
 		break;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 	case EVENT_ASSOCINFO:
@@ -2698,52 +2970,11 @@
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_reject(wpa_s, data);
 		else {
-#ifdef ANDROID_P2P
-			if(!wpa_s->current_ssid) {
-				wpa_printf(MSG_ERROR, "current_ssid == NULL");
-				break;
-			}
-			/* If assoc reject is reported by the driver, then avoid
-			 * waiting for  the authentication timeout. Cancel the
-			 * authentication timeout and retry the assoc.
-			 */
-			if(wpa_s->current_ssid->assoc_retry++ < 10) {
-				wpa_printf(MSG_ERROR, "Retrying assoc: %d ",
-								wpa_s->current_ssid->assoc_retry);
-
-				wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-				/* Clear the states */
-				wpa_sm_notify_disassoc(wpa_s->wpa);
-				wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
-				wpa_s->reassociate = 1;
-				if (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE) {
-					const u8 *bl_bssid = data->assoc_reject.bssid;
-					if (!bl_bssid || is_zero_ether_addr(bl_bssid))
-						bl_bssid = wpa_s->pending_bssid;
-					wpa_blacklist_add(wpa_s, bl_bssid);
-					wpa_supplicant_req_scan(wpa_s, 0, 0);
-				} else {
-					wpa_supplicant_req_scan(wpa_s, 1, 0);
-				}
-			} else if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
-				/* If we ASSOC_REJECT's hits threshold, disable the 
-			 	 * network
-			 	 */
-				wpa_printf(MSG_ERROR, "Assoc retry threshold reached. "
-				"Disabling the network");
-				wpa_s->current_ssid->assoc_retry = 0;
-				wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
-				wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
-			}
-#else
 			const u8 *bssid = data->assoc_reject.bssid;
 			if (bssid == NULL || is_zero_ether_addr(bssid))
 				bssid = wpa_s->pending_bssid;
 			wpas_connection_failed(wpa_s, bssid);
 			wpa_supplicant_mark_disassoc(wpa_s);
-#endif /* ANDROID_P2P */
 		}
 		break;
 	case EVENT_AUTH_TIMED_OUT:
@@ -2840,10 +3071,12 @@
 
 		wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
 				  data->ch_switch.ht_enabled,
-				  data->ch_switch.ch_offset);
+				  data->ch_switch.ch_offset,
+				  data->ch_switch.ch_width,
+				  data->ch_switch.cf1,
+				  data->ch_switch.cf2);
 		break;
 #endif /* CONFIG_AP */
-#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
 	case EVENT_RX_MGMT: {
 		u16 fc, stype;
 		const struct ieee80211_mgmt *mgmt;
@@ -2878,6 +3111,14 @@
 				break;
 			}
 #endif /* CONFIG_IBSS_RSN */
+
+			if (stype == WLAN_FC_STYPE_ACTION) {
+				wpas_event_rx_mgmt_action(
+					wpa_s, mgmt, data->rx_mgmt.frame_len,
+					data->rx_mgmt.freq);
+				break;
+			}
+
 			wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
 				"management frame in non-AP mode");
 			break;
@@ -2900,63 +3141,6 @@
 #endif /* CONFIG_AP */
 		break;
 		}
-#endif /* CONFIG_AP || CONFIG_IBSS_RSN */
-	case EVENT_RX_ACTION:
-		wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
-			" Category=%u DataLen=%d freq=%d MHz",
-			MAC2STR(data->rx_action.sa),
-			data->rx_action.category, (int) data->rx_action.len,
-			data->rx_action.freq);
-#ifdef CONFIG_IEEE80211R
-		if (data->rx_action.category == WLAN_ACTION_FT) {
-			ft_rx_action(wpa_s, data->rx_action.data,
-				     data->rx_action.len);
-			break;
-		}
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-#ifdef CONFIG_SME
-		if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
-			sme_sa_query_rx(wpa_s, data->rx_action.sa,
-					data->rx_action.data,
-					data->rx_action.len);
-			break;
-		}
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WNM
-		if (data->rx_action.category == WLAN_ACTION_WNM) {
-			ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
-			break;
-		}
-#endif /* CONFIG_WNM */
-#ifdef CONFIG_GAS
-		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
-		    gas_query_rx(wpa_s->gas, data->rx_action.da,
-				 data->rx_action.sa, data->rx_action.bssid,
-				 data->rx_action.data, data->rx_action.len,
-				 data->rx_action.freq) == 0)
-			break;
-#endif /* CONFIG_GAS */
-#ifdef CONFIG_TDLS
-		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
-		    data->rx_action.len >= 4 &&
-		    data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
-				"Response from " MACSTR,
-				MAC2STR(data->rx_action.sa));
-			break;
-		}
-#endif /* CONFIG_TDLS */
-#ifdef CONFIG_P2P
-		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
-				   data->rx_action.sa,
-				   data->rx_action.bssid,
-				   data->rx_action.category,
-				   data->rx_action.data,
-				   data->rx_action.len, data->rx_action.freq);
-#endif /* CONFIG_P2P */
-		break;
 	case EVENT_RX_PROBE_REQ:
 		if (data->rx_probe_req.sa == NULL ||
 		    data->rx_probe_req.ie == NULL)
@@ -3004,71 +3188,6 @@
 			wpa_s, data->remain_on_channel.freq);
 #endif /* CONFIG_P2P */
 		break;
-#ifdef CONFIG_P2P
-	case EVENT_P2P_DEV_FOUND: {
-		struct p2p_peer_info peer_info;
-
-		os_memset(&peer_info, 0, sizeof(peer_info));
-		if (data->p2p_dev_found.dev_addr)
-			os_memcpy(peer_info.p2p_device_addr,
-				  data->p2p_dev_found.dev_addr, ETH_ALEN);
-		if (data->p2p_dev_found.pri_dev_type)
-			os_memcpy(peer_info.pri_dev_type,
-				  data->p2p_dev_found.pri_dev_type,
-				  sizeof(peer_info.pri_dev_type));
-		if (data->p2p_dev_found.dev_name)
-			os_strlcpy(peer_info.device_name,
-				   data->p2p_dev_found.dev_name,
-				   sizeof(peer_info.device_name));
-		peer_info.config_methods = data->p2p_dev_found.config_methods;
-		peer_info.dev_capab = data->p2p_dev_found.dev_capab;
-		peer_info.group_capab = data->p2p_dev_found.group_capab;
-
-		/*
-		 * FIX: new_device=1 is not necessarily correct. We should
-		 * maintain a P2P peer database in wpa_supplicant and update
-		 * this information based on whether the peer is truly new.
-		 */
-		wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
-		break;
-		}
-	case EVENT_P2P_GO_NEG_REQ_RX:
-		wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
-				   data->p2p_go_neg_req_rx.dev_passwd_id);
-		break;
-	case EVENT_P2P_GO_NEG_COMPLETED:
-		wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
-		break;
-	case EVENT_P2P_PROV_DISC_REQUEST:
-		wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
-				   data->p2p_prov_disc_req.config_methods,
-				   data->p2p_prov_disc_req.dev_addr,
-				   data->p2p_prov_disc_req.pri_dev_type,
-				   data->p2p_prov_disc_req.dev_name,
-				   data->p2p_prov_disc_req.supp_config_methods,
-				   data->p2p_prov_disc_req.dev_capab,
-				   data->p2p_prov_disc_req.group_capab,
-				   NULL, 0);
-		break;
-	case EVENT_P2P_PROV_DISC_RESPONSE:
-		wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
-				    data->p2p_prov_disc_resp.config_methods);
-		break;
-	case EVENT_P2P_SD_REQUEST:
-		wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
-				data->p2p_sd_req.sa,
-				data->p2p_sd_req.dialog_token,
-				data->p2p_sd_req.update_indic,
-				data->p2p_sd_req.tlvs,
-				data->p2p_sd_req.tlvs_len);
-		break;
-	case EVENT_P2P_SD_RESPONSE:
-		wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
-				 data->p2p_sd_resp.update_indic,
-				 data->p2p_sd_resp.tlvs,
-				 data->p2p_sd_resp.tlvs_len);
-		break;
-#endif /* CONFIG_P2P */
 	case EVENT_EAPOL_RX:
 		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
 					data->eapol_rx.data,
@@ -3101,20 +3220,27 @@
 		break;
 	case EVENT_INTERFACE_DISABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+#ifdef CONFIG_P2P
+		if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO ||
+		    (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group &&
+		     wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) {
+			/*
+			 * The interface was externally disabled. Remove
+			 * it assuming an external entity will start a
+			 * new session if needed.
+			 */
+			wpas_p2p_disconnect(wpa_s);
+			break;
+		}
+#endif /* CONFIG_P2P */
+
 		wpa_supplicant_mark_disassoc(wpa_s);
+		radio_remove_works(wpa_s, NULL, 0);
+
 		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
 		break;
 	case EVENT_CHANNEL_LIST_CHANGED:
-		if (wpa_s->drv_priv == NULL)
-			break; /* Ignore event during drv initialization */
-
-		free_hw_features(wpa_s);
-		wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
-			wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
-
-#ifdef CONFIG_P2P
-		wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
+		wpa_supplicant_update_channel_list(wpa_s);
 		break;
 	case EVENT_INTERFACE_UNAVAILABLE:
 #ifdef CONFIG_P2P
@@ -3169,6 +3295,7 @@
 					 data->driver_gtk_rekey.replay_ctr);
 		break;
 	case EVENT_SCHED_SCAN_STOPPED:
+		wpa_s->pno = 0;
 		wpa_s->sched_scanning = 0;
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 
@@ -3176,17 +3303,29 @@
 			break;
 
 		/*
-		 * If we timed out, start a new sched scan to continue
-		 * searching for more SSIDs.
+		 * Start a new sched scan to continue searching for more SSIDs
+		 * either if timed out or PNO schedule scan is pending.
 		 */
-		if (wpa_s->sched_scan_timed_out)
-			wpa_supplicant_req_sched_scan(wpa_s);
+		if (wpa_s->sched_scan_timed_out || wpa_s->pno_sched_pending) {
+
+			if (wpa_supplicant_req_sched_scan(wpa_s) < 0 &&
+			    wpa_s->pno_sched_pending) {
+				wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO");
+			} else if (wpa_s->pno_sched_pending) {
+				wpa_s->pno_sched_pending = 0;
+				wpa_s->pno = 1;
+			}
+		}
+
 		break;
 	case EVENT_WPS_BUTTON_PUSHED:
 #ifdef CONFIG_WPS
 		wpas_wps_start_pbc(wpa_s, NULL, 0);
 #endif /* CONFIG_WPS */
 		break;
+	case EVENT_AVOID_FREQUENCIES:
+		wpa_supplicant_notify_avoid_freq(wpa_s, data);
+		break;
 	case EVENT_CONNECT_FAILED_REASON:
 #ifdef CONFIG_AP
 		if (!wpa_s->ap_iface || !data)
diff --git a/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant/examples/p2p-action.sh
index 8759f54..797d43a 100755
--- a/wpa_supplicant/examples/p2p-action.sh
+++ b/wpa_supplicant/examples/p2p-action.sh
@@ -34,13 +34,26 @@
 	    # start with -z to avoid that
 	    dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
 		-i $GIFNAME \
-		-F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z
+		-F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z -p 0
 	fi
     fi
     if [ "$4" = "client" ]; then
 	kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
 	rm /var/run/dhclient.leases-$GIFNAME
 	kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+	ipaddr=`echo "$*" | sed 's/.* ip_addr=\([^ ]*\).*/\1/'`
+	ipmask=`echo "$*" | sed 's/.* ip_mask=\([^ ]*\).*/\1/'`
+	goipaddr=`echo "$*" | sed 's/.* go_ip_addr=\([^ ]*\).*/\1/'`
+	if echo "$ipaddr$ipmask$goipaddr" | grep -q ' '; then
+	    ipaddr=""
+	    ipmask=""
+	    goipaddr=""
+	fi
+	if [ -n "$ipaddr" ]; then
+	    sudo ifconfig $GIFNAME "$ipaddr" netmask "$ipmask"
+	    sudo ip ro re default via "$goipaddr"
+	    exit 0
+	fi
 	dhclient -pf /var/run/dhclient-$GIFNAME.pid \
 	    -lf /var/run/dhclient.leases-$GIFNAME \
 	    -nw \
diff --git a/wpa_supplicant/examples/p2p-nfc.py b/wpa_supplicant/examples/p2p-nfc.py
new file mode 100644
index 0000000..91eba28
--- /dev/null
+++ b/wpa_supplicant/examples/p2p-nfc.py
@@ -0,0 +1,654 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import random
+import threading
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+include_wps_req = True
+include_p2p_req = True
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+    print txt
+    if summary_file:
+        with open(summary_file, 'a') as f:
+            f.write(txt + "\n")
+
+def success_report(txt):
+    summary(txt)
+    if success_file:
+        with open(success_file, 'a') as f:
+            f.write(txt + "\n")
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError, error:
+            print "Could not find wpa_supplicant: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No wpa_supplicant control interface found"
+        return None
+
+    for ctrl in ifaces:
+        if ifname:
+            if ifname not in ctrl:
+                continue
+        try:
+            print "Trying to use control interface " + ctrl
+            wpas = wpaspy.Ctrl(ctrl)
+            return wpas
+        except Exception, e:
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return False
+    cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex")
+    global force_freq
+    if force_freq:
+        cmd = cmd + " freq=" + force_freq
+    if "FAIL" in wpas.request(cmd):
+        return False
+    return True
+
+
+def wpas_get_handover_req():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+    if "FAIL" in res:
+        return None
+    return res.decode("hex")
+
+def wpas_get_handover_req_wps():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
+    if "FAIL" in res:
+        return None
+    return res.decode("hex")
+
+
+def wpas_get_handover_sel(tag=False):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    if tag:
+        res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+    else:
+	res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+    if "FAIL" in res:
+        return None
+    return res.decode("hex")
+
+
+def wpas_get_handover_sel_wps():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR");
+    if "FAIL" in res:
+        return None
+    return res.rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex")
+    global force_freq
+    if force_freq:
+        cmd = cmd + " freq=" + force_freq
+    return wpas.request(cmd)
+
+
+def wpas_report_handover_wsc(req, sel, type):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")
+    if force_freq:
+        cmd = cmd + " freq=" + force_freq
+    return wpas.request(cmd)
+
+
+def p2p_handover_client(llc):
+    message = nfc.ndef.HandoverRequestMessage(version="1.2")
+    message.nonce = random.randint(0, 0xffff)
+
+    global include_p2p_req
+    if include_p2p_req:
+        data = wpas_get_handover_req()
+        if (data == None):
+            summary("Could not get handover request carrier record from wpa_supplicant")
+            return
+        print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+        datamsg = nfc.ndef.Message(data)
+        message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+    global include_wps_req
+    if include_wps_req:
+        print "Handover request (pre-WPS):"
+        try:
+            print message.pretty()
+        except Exception, e:
+            print e
+
+        data = wpas_get_handover_req_wps()
+        if data:
+            print "Add WPS request in addition to P2P"
+            datamsg = nfc.ndef.Message(data)
+            message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+    print "Handover request:"
+    try:
+        print message.pretty()
+    except Exception, e:
+        print e
+    print str(message).encode("hex")
+
+    client = nfc.handover.HandoverClient(llc)
+    try:
+        summary("Trying to initiate NFC connection handover")
+        client.connect()
+        summary("Connected for handover")
+    except nfc.llcp.ConnectRefused:
+        summary("Handover connection refused")
+        client.close()
+        return
+    except Exception, e:
+        summary("Other exception: " + str(e))
+        client.close()
+        return
+
+    summary("Sending handover request")
+
+    if not client.send(message):
+        summary("Failed to send handover request")
+        client.close()
+        return
+
+    summary("Receiving handover response")
+    message = client._recv()
+    if message is None:
+        summary("No response received")
+        client.close()
+        return
+    if message.type != "urn:nfc:wkt:Hs":
+        summary("Response was not Hs - received: " + message.type)
+        client.close()
+        return
+
+    print "Received message"
+    try:
+        print message.pretty()
+    except Exception, e:
+        print e
+    print str(message).encode("hex")
+    message = nfc.ndef.HandoverSelectMessage(message)
+    summary("Handover select received")
+    try:
+        print message.pretty()
+    except Exception, e:
+        print e
+
+    for carrier in message.carriers:
+        print "Remote carrier type: " + carrier.type
+        if carrier.type == "application/vnd.wfa.p2p":
+            print "P2P carrier type match - send to wpa_supplicant"
+            if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
+                success_report("P2P handover reported successfully (initiator)")
+            else:
+                summary("P2P handover report rejected")
+            break
+
+    print "Remove peer"
+    client.close()
+    print "Done with handover"
+    global only_one
+    if only_one:
+        print "only_one -> stop loop"
+        global continue_loop
+        continue_loop = False
+
+    global no_wait
+    if no_wait:
+        print "Trying to exit.."
+        global terminate_now
+        terminate_now = True
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+    def __init__(self, llc):
+        super(HandoverServer, self).__init__(llc)
+        self.sent_carrier = None
+        self.ho_server_processing = False
+        self.success = False
+
+    # override to avoid parser error in request/response.pretty() in nfcpy
+    # due to new WSC handover format
+    def _process_request(self, request):
+        summary("received handover request {}".format(request.type))
+        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+        if not request.type == 'urn:nfc:wkt:Hr':
+            summary("not a handover request")
+        else:
+            try:
+                request = nfc.ndef.HandoverRequestMessage(request)
+            except nfc.ndef.DecodeError as e:
+                summary("error decoding 'Hr' message: {}".format(e))
+            else:
+                response = self.process_request(request)
+        summary("send handover response {}".format(response.type))
+        return response
+
+    def process_request(self, request):
+        self.ho_server_processing = True
+        clear_raw_mode()
+        print "HandoverServer - request received"
+        try:
+            print "Parsed handover request: " + request.pretty()
+        except Exception, e:
+            print e
+
+        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+        found = False
+
+        for carrier in request.carriers:
+            print "Remote carrier type: " + carrier.type
+            if carrier.type == "application/vnd.wfa.p2p":
+                print "P2P carrier type match - add P2P carrier record"
+                found = True
+                self.received_carrier = carrier.record
+                print "Carrier record:"
+                try:
+                    print carrier.record.pretty()
+                except Exception, e:
+                    print e
+                data = wpas_get_handover_sel()
+                if data is None:
+                    print "Could not get handover select carrier record from wpa_supplicant"
+                    continue
+                print "Handover select carrier record from wpa_supplicant:"
+                print data.encode("hex")
+                self.sent_carrier = data
+                if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
+                    success_report("P2P handover reported successfully (responder)")
+                else:
+                    summary("P2P handover report rejected")
+                    break
+
+                message = nfc.ndef.Message(data);
+                sel.add_carrier(message[0], "active", message[1:])
+                break
+
+        for carrier in request.carriers:
+            if found:
+                break
+            print "Remote carrier type: " + carrier.type
+            if carrier.type == "application/vnd.wfa.wsc":
+                print "WSC carrier type match - add WSC carrier record"
+                found = True
+                self.received_carrier = carrier.record
+                print "Carrier record:"
+                try:
+                    print carrier.record.pretty()
+                except Exception, e:
+                    print e
+                data = wpas_get_handover_sel_wps()
+                if data is None:
+                    print "Could not get handover select carrier record from wpa_supplicant"
+                    continue
+                print "Handover select carrier record from wpa_supplicant:"
+                print data.encode("hex")
+                self.sent_carrier = data
+                if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
+                    success_report("WSC handover reported successfully")
+                else:
+                    summary("WSC handover report rejected")
+                    break
+
+                message = nfc.ndef.Message(data);
+                sel.add_carrier(message[0], "active", message[1:])
+                found = True
+                break
+
+        print "Handover select:"
+        try:
+            print sel.pretty()
+        except Exception, e:
+            print e
+        print str(sel).encode("hex")
+
+        summary("Sending handover select")
+        self.success = True
+        return sel
+
+
+def clear_raw_mode():
+    import sys, tty, termios
+    global prev_tcgetattr, in_raw_mode
+    if not in_raw_mode:
+        return
+    fd = sys.stdin.fileno()
+    termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+    in_raw_mode = False
+
+
+def getch():
+    import sys, tty, termios, select
+    global prev_tcgetattr, in_raw_mode
+    fd = sys.stdin.fileno()
+    prev_tcgetattr = termios.tcgetattr(fd)
+    ch = None
+    try:
+        tty.setraw(fd)
+        in_raw_mode = True
+        [i, o, e] = select.select([fd], [], [], 0.05)
+        if i:
+            ch = sys.stdin.read(1)
+    finally:
+        termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+        in_raw_mode = False
+    return ch
+
+
+def p2p_tag_read(tag):
+    success = False
+    if len(tag.ndef.message):
+        for record in tag.ndef.message:
+            print "record type " + record.type
+            if record.type == "application/vnd.wfa.wsc":
+                summary("WPS tag - send to wpa_supplicant")
+                success = wpas_tag_read(tag.ndef.message)
+                break
+            if record.type == "application/vnd.wfa.p2p":
+                summary("P2P tag - send to wpa_supplicant")
+                success = wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        summary("Empty tag")
+
+    if success:
+        success_report("Tag read succeeded")
+
+    return success
+
+
+def rdwr_connected_p2p_write(tag):
+    summary("Tag found - writing - " + str(tag))
+    global p2p_sel_data
+    tag.ndef.message = str(p2p_sel_data)
+    success_report("Tag write succeeded")
+    print "Done - remove tag"
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
+    global p2p_sel_wait_remove
+    return p2p_sel_wait_remove
+
+def wps_write_p2p_handover_sel(clf, wait_remove=True):
+    print "Write P2P handover select"
+    data = wpas_get_handover_sel(tag=True)
+    if (data == None):
+        summary("Could not get P2P handover select from wpa_supplicant")
+        return
+
+    global p2p_sel_wait_remove
+    p2p_sel_wait_remove = wait_remove
+    global p2p_sel_data
+    p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
+    message = nfc.ndef.Message(data);
+    p2p_sel_data.add_carrier(message[0], "active", message[1:])
+    print "Handover select:"
+    try:
+        print p2p_sel_data.pretty()
+    except Exception, e:
+        print e
+    print str(p2p_sel_data).encode("hex")
+
+    print "Touch an NFC tag"
+    clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
+
+
+def rdwr_connected(tag):
+    global only_one, no_wait
+    summary("Tag connected: " + str(tag))
+
+    if tag.ndef:
+        print "NDEF tag: " + tag.type
+        try:
+            print tag.ndef.message.pretty()
+        except Exception, e:
+            print e
+        success = p2p_tag_read(tag)
+        if only_one and success:
+            global continue_loop
+            continue_loop = False
+    else:
+        summary("Not an NDEF tag - remove tag")
+        return True
+
+    return not no_wait
+
+
+def llcp_worker(llc):
+    global init_on_touch
+    if init_on_touch:
+            print "Starting handover client"
+            p2p_handover_client(llc)
+            return
+
+    global no_input
+    if no_input:
+        print "Wait for handover to complete"
+    else:
+        print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
+    global srv
+    global wait_connection
+    while not wait_connection and srv.sent_carrier is None:
+        if srv.ho_server_processing:
+            time.sleep(0.025)
+        elif no_input:
+            time.sleep(0.5)
+        else:
+            global include_wps_req, include_p2p_req
+            res = getch()
+            if res == 'i':
+                include_wps_req = True
+                include_p2p_req = True
+            elif res == 'p':
+                include_wps_req = False
+                include_p2p_req = True
+            elif res == 'w':
+                include_wps_req = True
+                include_p2p_req = False
+            else:
+                continue
+            clear_raw_mode()
+            print "Starting handover client"
+            p2p_handover_client(llc)
+            return
+            
+    clear_raw_mode()
+    print "Exiting llcp_worker thread"
+
+def llcp_startup(clf, llc):
+    print "Start LLCP server"
+    global srv
+    srv = HandoverServer(llc)
+    return llc
+
+def llcp_connected(llc):
+    print "P2P LLCP connected"
+    global wait_connection
+    wait_connection = False
+    global init_on_touch
+    if not init_on_touch:
+        global srv
+        srv.start()
+    if init_on_touch or not no_input:
+        threading.Thread(target=llcp_worker, args=(llc,)).start()
+    return True
+
+def terminate_loop():
+    global terminate_now
+    return terminate_now
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations')
+    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+                        action='store_const', dest='loglevel',
+                        help='verbose debug output')
+    parser.add_argument('-q', const=logging.WARNING, action='store_const',
+                        dest='loglevel', help='be quiet')
+    parser.add_argument('--only-one', '-1', action='store_true',
+                        help='run only one operation and exit')
+    parser.add_argument('--init-on-touch', '-I', action='store_true',
+                        help='initiate handover on touch')
+    parser.add_argument('--no-wait', action='store_true',
+                        help='do not wait for tag to be removed before exiting')
+    parser.add_argument('--ifname', '-i',
+                        help='network interface name')
+    parser.add_argument('--no-wps-req', '-N', action='store_true',
+                        help='do not include WPS carrier record in request')
+    parser.add_argument('--no-input', '-a', action='store_true',
+                        help='do not use stdout input to initiate handover')
+    parser.add_argument('--tag-read-only', '-t', action='store_true',
+                        help='tag read only (do not allow connection handover)')
+    parser.add_argument('--handover-only', action='store_true',
+                        help='connection handover only (do not allow tag read)')
+    parser.add_argument('--freq', '-f',
+                        help='forced frequency of operating channel in MHz')
+    parser.add_argument('--summary',
+                        help='summary file for writing status updates')
+    parser.add_argument('--success',
+                        help='success file for writing success update')
+    parser.add_argument('command', choices=['write-p2p-sel'],
+                        nargs='?')
+    args = parser.parse_args()
+
+    global only_one
+    only_one = args.only_one
+
+    global no_wait
+    no_wait = args.no_wait
+
+    global force_freq
+    force_freq = args.freq
+
+    logging.basicConfig(level=args.loglevel)
+
+    global init_on_touch
+    init_on_touch = args.init_on_touch
+
+    if args.ifname:
+        global ifname
+        ifname = args.ifname
+        print "Selected ifname " + ifname
+
+    if args.no_wps_req:
+        global include_wps_req
+        include_wps_req = False
+
+    if args.summary:
+        global summary_file
+        summary_file = args.summary
+
+    if args.success:
+        global success_file
+        success_file = args.success
+
+    if args.no_input:
+        global no_input
+        no_input = True
+
+    clf = nfc.ContactlessFrontend()
+    global wait_connection
+
+    try:
+        if not clf.open("usb"):
+            print "Could not open connection with an NFC device"
+            raise SystemExit
+
+        if args.command == "write-p2p-sel":
+            wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait)
+            raise SystemExit
+
+        global continue_loop
+        while continue_loop:
+            print "Waiting for a tag or peer to be touched"
+            wait_connection = True
+            try:
+                if args.tag_read_only:
+                    if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+                        break
+                elif args.handover_only:
+                    if not clf.connect(llcp={'on-startup': llcp_startup,
+                                             'on-connect': llcp_connected},
+                                       terminate=terminate_loop):
+                        break
+                else:
+                    if not clf.connect(rdwr={'on-connect': rdwr_connected},
+                                       llcp={'on-startup': llcp_startup,
+                                             'on-connect': llcp_connected},
+                                       terminate=terminate_loop):
+                        break
+            except Exception, e:
+                print "clf.connect failed"
+
+            global srv
+            if only_one and srv and srv.success:
+                raise SystemExit
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index d6dec85..7459eb9 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -10,7 +10,8 @@
 import sys
 import time
 import random
-import StringIO
+import threading
+import argparse
 
 import nfc
 import nfc.ndef
@@ -18,11 +19,27 @@
 import nfc.handover
 
 import logging
-logging.basicConfig()
 
 import wpaspy
 
 wpas_ctrl = '/var/run/wpa_supplicant'
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+    print txt
+    if summary_file:
+        with open(summary_file, 'a') as f:
+            f.write(txt + "\n")
+
+def success_report(txt):
+    summary(txt)
+    if success_file:
+        with open(success_file, 'a') as f:
+            f.write(txt + "\n")
 
 def wpas_connect():
     ifaces = []
@@ -50,7 +67,7 @@
     wpas = wpas_connect()
     if (wpas == None):
         return False
-    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")):
+    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
         return False
     return True
 
@@ -71,21 +88,29 @@
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
+    ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid)
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_get_password_token():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
-
+    ret = wpas.request("WPS_NFC_TOKEN NDEF")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 def wpas_get_handover_req():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
+    ret = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_get_handover_sel(uuid):
@@ -93,8 +118,12 @@
     if (wpas == None):
         return None
     if uuid is None:
-        return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
-    return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
+        res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
+    else:
+	res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip()
+    if "FAIL" in res:
+	return None
+    return res.decode("hex")
 
 
 def wpas_report_handover(req, sel, type):
@@ -107,159 +136,176 @@
 
 
 class HandoverServer(nfc.handover.HandoverServer):
-    def __init__(self):
-        super(HandoverServer, self).__init__()
+    def __init__(self, llc):
+        super(HandoverServer, self).__init__(llc)
+        self.sent_carrier = None
+        self.ho_server_processing = False
+        self.success = False
+
+    # override to avoid parser error in request/response.pretty() in nfcpy
+    # due to new WSC handover format
+    def _process_request(self, request):
+        summary("received handover request {}".format(request.type))
+        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+        if not request.type == 'urn:nfc:wkt:Hr':
+            summary("not a handover request")
+        else:
+            try:
+                request = nfc.ndef.HandoverRequestMessage(request)
+            except nfc.ndef.DecodeError as e:
+                summary("error decoding 'Hr' message: {}".format(e))
+            else:
+                response = self.process_request(request)
+        summary("send handover response {}".format(response.type))
+        return response
 
     def process_request(self, request):
-        print "HandoverServer - request received"
-        print "Parsed handover request: " + request.pretty()
+        self.ho_server_processing = True
+        summary("HandoverServer - request received")
+        try:
+            print "Parsed handover request: " + request.pretty()
+        except Exception, e:
+            print e
 
         sel = nfc.ndef.HandoverSelectMessage(version="1.2")
 
         for carrier in request.carriers:
             print "Remote carrier type: " + carrier.type
             if carrier.type == "application/vnd.wfa.wsc":
-                print "WPS carrier type match - add WPS carrier record"
-                self.received_carrier = carrier.record
+                summary("WPS carrier type match - add WPS carrier record")
                 data = wpas_get_handover_sel(self.uuid)
                 if data is None:
-                    print "Could not get handover select carrier record from wpa_supplicant"
+                    summary("Could not get handover select carrier record from wpa_supplicant")
                     continue
                 print "Handover select carrier record from wpa_supplicant:"
                 print data.encode("hex")
                 self.sent_carrier = data
+                if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
+                    success_report("Handover reported successfully (responder)")
+                else:
+                    summary("Handover report rejected (responder)")
 
                 message = nfc.ndef.Message(data);
                 sel.add_carrier(message[0], "active", message[1:])
 
         print "Handover select:"
-        print sel.pretty()
+        try:
+            print sel.pretty()
+        except Exception, e:
+            print e
         print str(sel).encode("hex")
 
-        print "Sending handover select"
+        summary("Sending handover select")
+        self.success = True
         return sel
 
 
-def wps_handover_resp(peer, uuid):
-    if uuid is None:
-        print "Trying to handle WPS handover"
-    else:
-        print "Trying to handle WPS handover with AP " + uuid
-
-    srv = HandoverServer()
-    srv.sent_carrier = None
-    srv.uuid = uuid
-
-    nfc.llcp.activate(peer);
-
-    try:
-        print "Trying handover";
-        srv.start()
-        print "Wait for disconnect"
-        while nfc.llcp.connected():
-            time.sleep(0.1)
-        print "Disconnected after handover"
-    except nfc.llcp.ConnectRefused:
-        print "Handover connection refused"
-        nfc.llcp.shutdown()
-        return
-
-    if srv.sent_carrier:
-        wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
-
-    print "Remove peer"
-    nfc.llcp.shutdown()
-    print "Done with handover"
-    time.sleep(1)
-
-
-def wps_handover_init(peer):
-    print "Trying to initiate WPS handover"
+def wps_handover_init(llc):
+    summary("Trying to initiate WPS handover")
 
     data = wpas_get_handover_req()
     if (data == None):
-        print "Could not get handover request carrier record from wpa_supplicant"
+        summary("Could not get handover request carrier record from wpa_supplicant")
         return
     print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
-    record = nfc.ndef.Record()
-    f = StringIO.StringIO(data)
-    record._read(f)
-    record = nfc.ndef.HandoverCarrierRecord(record)
-    print "Parsed handover request carrier record:"
-    print record.pretty()
 
     message = nfc.ndef.HandoverRequestMessage(version="1.2")
     message.nonce = random.randint(0, 0xffff)
-    message.add_carrier(record, "active")
+    datamsg = nfc.ndef.Message(data)
+    message.add_carrier(datamsg[0], "active", datamsg[1:])
 
     print "Handover request:"
-    print message.pretty()
-
-    nfc.llcp.activate(peer);
-
-    client = nfc.handover.HandoverClient()
     try:
-        print "Trying handover";
+        print message.pretty()
+    except Exception, e:
+        print e
+    print str(message).encode("hex")
+
+    client = nfc.handover.HandoverClient(llc)
+    try:
+        summary("Trying to initiate NFC connection handover")
         client.connect()
-        print "Connected for handover"
+        summary("Connected for handover")
     except nfc.llcp.ConnectRefused:
-        print "Handover connection refused"
-        nfc.llcp.shutdown()
+        summary("Handover connection refused")
+        client.close()
+        return
+    except Exception, e:
+        summary("Other exception: " + str(e))
         client.close()
         return
 
-    print "Sending handover request"
+    summary("Sending handover request")
 
     if not client.send(message):
-        print "Failed to send handover request"
+        summary("Failed to send handover request")
+        client.close()
+        return
 
-    print "Receiving handover response"
+    summary("Receiving handover response")
     message = client._recv()
     if message is None:
-        print "No response received"
-        nfc.llcp.shutdown()
+        summary("No response received")
         client.close()
         return
     if message.type != "urn:nfc:wkt:Hs":
-        print "Response was not Hs - received: " + message.type
-        nfc.llcp.shutdown()
+        summary("Response was not Hs - received: " + message.type)
         client.close()
         return
 
     print "Received message"
-    print message.pretty()
+    try:
+        print message.pretty()
+    except Exception, e:
+        print e
+    print str(message).encode("hex")
     message = nfc.ndef.HandoverSelectMessage(message)
-    print "Handover select received"
-    print message.pretty()
+    summary("Handover select received")
+    try:
+        print message.pretty()
+    except Exception, e:
+        print e
 
     for carrier in message.carriers:
         print "Remote carrier type: " + carrier.type
         if carrier.type == "application/vnd.wfa.wsc":
             print "WPS carrier type match - send to wpa_supplicant"
-            wpas_report_handover(data, carrier.record, "INIT")
-            wifi = nfc.ndef.WifiConfigRecord(carrier.record)
-            print wifi.pretty()
+            if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
+                success_report("Handover reported successfully (initiator)")
+            else:
+                summary("Handover report rejected (initiator)")
+            # nfcpy does not support the new format..
+            #wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+            #print wifi.pretty()
 
     print "Remove peer"
-    nfc.llcp.shutdown()
     client.close()
     print "Done with handover"
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
 
+    global no_wait
+    if no_wait:
+        print "Trying to exit.."
+        global terminate_now
+        terminate_now = True
 
 def wps_tag_read(tag, wait_remove=True):
     success = False
     if len(tag.ndef.message):
-        message = nfc.ndef.Message(tag.ndef.message)
-        print "message type " + message.type
-
-        for record in message:
+        for record in tag.ndef.message:
             print "record type " + record.type
             if record.type == "application/vnd.wfa.wsc":
-                print "WPS tag - send to wpa_supplicant"
+                summary("WPS tag - send to wpa_supplicant")
                 success = wpas_tag_read(tag.ndef.message)
                 break
     else:
-        print "Empty tag"
+        summary("Empty tag")
+
+    if success:
+        success_report("Tag read succeeded")
 
     if wait_remove:
         print "Remove tag"
@@ -269,166 +315,204 @@
     return success
 
 
+def rdwr_connected_write(tag):
+    summary("Tag found - writing - " + str(tag))
+    global write_data
+    tag.ndef.message = str(write_data)
+    success_report("Tag write succeeded")
+    print "Done - remove tag"
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
+    global write_wait_remove
+    while write_wait_remove and tag.is_present:
+        time.sleep(0.1)
+
 def wps_write_config_tag(clf, id=None, wait_remove=True):
     print "Write WPS config token"
-    data = wpas_get_config_token(id)
-    if (data == None):
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_config_token(id)
+    if write_data == None:
         print "Could not get WPS config token from wpa_supplicant"
         sys.exit(1)
         return
-
     print "Touch an NFC tag"
-    while True:
-        tag = clf.poll()
-        if tag == None:
-            time.sleep(0.1)
-            continue
-        break
-
-    print "Tag found - writing"
-    tag.ndef.message = data
-    print "Done - remove tag"
-    while wait_remove and tag.is_present:
-        time.sleep(0.1)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-def wps_write_er_config_tag(clf, uuid):
+def wps_write_er_config_tag(clf, uuid, wait_remove=True):
     print "Write WPS ER config token"
-    data = wpas_get_er_config_token(uuid)
-    if (data == None):
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_er_config_token(uuid)
+    if write_data == None:
         print "Could not get WPS config token from wpa_supplicant"
         return
 
     print "Touch an NFC tag"
-    while True:
-        tag = clf.poll()
-        if tag == None:
-            time.sleep(0.1)
-            continue
-        break
-
-    print "Tag found - writing"
-    tag.ndef.message = data
-    print "Done - remove tag"
-    while tag.is_present:
-        time.sleep(0.1)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
 def wps_write_password_tag(clf, wait_remove=True):
     print "Write WPS password token"
-    data = wpas_get_password_token()
-    if (data == None):
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_password_token()
+    if write_data == None:
         print "Could not get WPS password token from wpa_supplicant"
         return
 
     print "Touch an NFC tag"
-    while True:
-        tag = clf.poll()
-        if tag == None:
-            time.sleep(0.1)
-            continue
-        break
-
-    print "Tag found - writing"
-    tag.ndef.message = data
-    print "Done - remove tag"
-    while wait_remove and tag.is_present:
-        time.sleep(0.1)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-def find_peer(clf):
-    while True:
-        if nfc.llcp.connected():
-            print "LLCP connected"
-        general_bytes = nfc.llcp.startup({})
-        peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
-        if isinstance(peer, nfc.DEP):
-            print "listen -> DEP";
-            if peer.general_bytes.startswith("Ffm"):
-                print "Found DEP"
-                return peer
-            print "mismatch in general_bytes"
-            print peer.general_bytes
+def rdwr_connected(tag):
+    global only_one, no_wait
+    summary("Tag connected: " + str(tag))
 
-        peer = clf.poll(general_bytes)
-        if isinstance(peer, nfc.DEP):
-            print "poll -> DEP";
-            if peer.general_bytes.startswith("Ffm"):
-                print "Found DEP"
-                return peer
-            print "mismatch in general_bytes"
-            print peer.general_bytes
+    if tag.ndef:
+        print "NDEF tag: " + tag.type
+        try:
+            print tag.ndef.message.pretty()
+        except Exception, e:
+            print e
+        success = wps_tag_read(tag, not only_one)
+        if only_one and success:
+            global continue_loop
+            continue_loop = False
+    else:
+        summary("Not an NDEF tag - remove tag")
+        return True
 
-        if peer:
-            print "Found tag"
-            return peer
+    return not no_wait
 
 
+def llcp_worker(llc):
+    global arg_uuid
+    if arg_uuid is None:
+        wps_handover_init(llc)
+        print "Exiting llcp_worker thread"
+        return
+
+    global srv
+    global wait_connection
+    while not wait_connection and srv.sent_carrier is None:
+        if srv.ho_server_processing:
+            time.sleep(0.025)
+
+def llcp_startup(clf, llc):
+    global arg_uuid
+    if arg_uuid:
+        print "Start LLCP server"
+        global srv
+        srv = HandoverServer(llc)
+        if arg_uuid is "ap":
+            print "Trying to handle WPS handover"
+            srv.uuid = None
+        else:
+            print "Trying to handle WPS handover with AP " + arg_uuid
+            srv.uuid = arg_uuid
+    return llc
+
+def llcp_connected(llc):
+    print "P2P LLCP connected"
+    global wait_connection
+    wait_connection = False
+    global arg_uuid
+    if arg_uuid:
+        global srv
+        srv.start()
+    else:
+        threading.Thread(target=llcp_worker, args=(llc,)).start()
+    print "llcp_connected returning"
+    return True
+
+
+def terminate_loop():
+    global terminate_now
+    return terminate_now
+
 def main():
     clf = nfc.ContactlessFrontend()
 
+    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations')
+    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+                        action='store_const', dest='loglevel',
+                        help='verbose debug output')
+    parser.add_argument('-q', const=logging.WARNING, action='store_const',
+                        dest='loglevel', help='be quiet')
+    parser.add_argument('--only-one', '-1', action='store_true',
+                        help='run only one operation and exit')
+    parser.add_argument('--no-wait', action='store_true',
+                        help='do not wait for tag to be removed before exiting')
+    parser.add_argument('--uuid',
+                        help='UUID of an AP (used for WPS ER operations)')
+    parser.add_argument('--id',
+                        help='network id (used for WPS ER operations)')
+    parser.add_argument('--summary',
+                        help='summary file for writing status updates')
+    parser.add_argument('--success',
+                        help='success file for writing success update')
+    parser.add_argument('command', choices=['write-config',
+                                            'write-er-config',
+                                            'write-password'],
+                        nargs='?')
+    args = parser.parse_args()
+
+    global arg_uuid
+    arg_uuid = args.uuid
+
+    global only_one
+    only_one = args.only_one
+
+    global no_wait
+    no_wait = args.no_wait
+
+    if args.summary:
+        global summary_file
+        summary_file = args.summary
+
+    if args.success:
+        global success_file
+        success_file = args.success
+
+    logging.basicConfig(level=args.loglevel)
+
     try:
-        arg_uuid = None
-        if len(sys.argv) > 1 and sys.argv[1] != '-1':
-            arg_uuid = sys.argv[1]
-
-        if len(sys.argv) > 1 and sys.argv[1] == '-1':
-            only_one = True
-        else:
-            only_one = False
-
-        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
-            wps_write_config_tag(clf)
+        if not clf.open("usb"):
+            print "Could not open connection with an NFC device"
             raise SystemExit
 
-        if len(sys.argv) > 1 and sys.argv[1] == "write-config-no-wait":
-            wps_write_config_tag(clf, wait_remove=False)
+        if args.command == "write-config":
+            wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait)
             raise SystemExit
 
-        if len(sys.argv) > 2 and sys.argv[1] == "write-config-id":
-            wps_write_config_tag(clf, sys.argv[2])
+        if args.command == "write-er-config":
+            wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait)
             raise SystemExit
 
-        if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
-            wps_write_er_config_tag(clf, sys.argv[2])
+        if args.command == "write-password":
+            wps_write_password_tag(clf, wait_remove=not args.no_wait)
             raise SystemExit
 
-        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
-            wps_write_password_tag(clf)
-            raise SystemExit
-
-        if len(sys.argv) > 1 and sys.argv[1] == "write-password-no-wait":
-            wps_write_password_tag(clf, wait_remove=False)
-            raise SystemExit
-
-        while True:
+        global continue_loop
+        while continue_loop:
             print "Waiting for a tag or peer to be touched"
-
-            tag = find_peer(clf)
-            if isinstance(tag, nfc.DEP):
-                if arg_uuid is None:
-                    wps_handover_init(tag)
-                elif arg_uuid is "ap":
-                    wps_handover_resp(tag, None)
-                else:
-                    wps_handover_resp(tag, arg_uuid)
-                if only_one:
+            wait_connection = True
+            try:
+                if not clf.connect(rdwr={'on-connect': rdwr_connected},
+                                   llcp={'on-startup': llcp_startup,
+                                         'on-connect': llcp_connected},
+                                   terminate=terminate_loop):
                     break
-                continue
+            except Exception, e:
+                print "clf.connect failed"
 
-            if tag.ndef:
-                success = wps_tag_read(tag, not only_one)
-                if only_one:
-                    if not success:
-                        sys.exit(1)
-                    break
-                continue
-
-            print "Not an NDEF tag - remove tag"
-            if only_one:
-                sys.exit(1)
-            while tag.is_present:
-                time.sleep(0.1)
+            global srv
+            if only_one and srv and srv.success:
+                raise SystemExit
 
     except KeyboardInterrupt:
         raise SystemExit
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 06a97d3..b255847 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -1,7 +1,8 @@
 /*
  * Generic advertisement service (GAS) query
  * Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -13,6 +14,8 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "offchannel.h"
@@ -28,6 +31,7 @@
  */
 struct gas_query_pending {
 	struct dl_list list;
+	struct gas_query *gas;
 	u8 addr[ETH_ALEN];
 	u8 dialog_token;
 	u8 next_frag_id;
@@ -35,6 +39,7 @@
 	unsigned int offchannel_tx_started:1;
 	int freq;
 	u16 status_code;
+	struct wpabuf *req;
 	struct wpabuf *adv_proto;
 	struct wpabuf *resp;
 	void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -50,6 +55,8 @@
 struct gas_query {
 	struct wpa_supplicant *wpa_s;
 	struct dl_list pending; /* struct gas_query_pending */
+	struct gas_query_pending *current;
+	struct wpa_radio_work *work;
 };
 
 
@@ -77,10 +84,58 @@
 }
 
 
+static const char * gas_result_txt(enum gas_query_result result)
+{
+	switch (result) {
+	case GAS_QUERY_SUCCESS:
+		return "SUCCESS";
+	case GAS_QUERY_FAILURE:
+		return "FAILURE";
+	case GAS_QUERY_TIMEOUT:
+		return "TIMEOUT";
+	case GAS_QUERY_PEER_ERROR:
+		return "PEER_ERROR";
+	case GAS_QUERY_INTERNAL_ERROR:
+		return "INTERNAL_ERROR";
+	case GAS_QUERY_CANCELLED:
+		return "CANCELLED";
+	case GAS_QUERY_DELETED_AT_DEINIT:
+		return "DELETED_AT_DEINIT";
+	}
+
+	return "N/A";
+}
+
+
+static void gas_query_free(struct gas_query_pending *query, int del_list)
+{
+	struct gas_query *gas = query->gas;
+
+	if (del_list)
+		dl_list_del(&query->list);
+
+	if (gas->work && gas->work->ctx == query) {
+		radio_work_done(gas->work);
+		gas->work = NULL;
+	}
+
+	wpabuf_free(query->req);
+	wpabuf_free(query->adv_proto);
+	wpabuf_free(query->resp);
+	os_free(query);
+}
+
+
 static void gas_query_done(struct gas_query *gas,
 			   struct gas_query_pending *query,
 			   enum gas_query_result result)
 {
+	wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
+		" dialog_token=%u freq=%d status_code=%u result=%s",
+		MAC2STR(query->addr), query->dialog_token, query->freq,
+		query->status_code, gas_result_txt(result));
+	if (gas->current == query)
+		gas->current = NULL;
 	if (query->offchannel_tx_started)
 		offchannel_send_action_done(gas->wpa_s);
 	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
@@ -88,9 +143,7 @@
 	dl_list_del(&query->list);
 	query->cb(query->ctx, query->addr, query->dialog_token, result,
 		  query->adv_proto, query->resp, query->status_code);
-	wpabuf_free(query->adv_proto);
-	wpabuf_free(query->resp);
-	os_free(query);
+	gas_query_free(query, 0);
 }
 
 
@@ -138,17 +191,70 @@
 }
 
 
+static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
+				unsigned int freq, const u8 *dst,
+				const u8 *src, const u8 *bssid,
+				const u8 *data, size_t data_len,
+				enum offchannel_send_action_result result)
+{
+	struct gas_query_pending *query;
+	struct gas_query *gas = wpa_s->gas;
+
+	if (gas->current == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+			   MACSTR " result=%d - no query in progress",
+			   freq, MAC2STR(dst), result);
+		return;
+	}
+
+	query = gas->current;
+
+	wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+		   " result=%d query=%p dialog_token=%u",
+		   freq, MAC2STR(dst), result, query, query->dialog_token);
+	if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+		return;
+	}
+
+	if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+				       gas_query_timeout, gas, query);
+	}
+	if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+		eloop_cancel_timeout(gas_query_timeout, gas, query);
+		eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+	}
+}
+
+
+static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	if (wpa_s->current_ssid == NULL ||
+	    wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
+	    os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
+		return 0;
+	return wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
+
 static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
 			struct wpabuf *req)
 {
-	int res;
+	int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+
 	wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
-		   "freq=%d", MAC2STR(query->addr),
-		   (unsigned int) wpabuf_len(req), query->freq);
+		   "freq=%d prot=%d", MAC2STR(query->addr),
+		   (unsigned int) wpabuf_len(req), query->freq, prot);
+	if (prot) {
+		u8 *categ = wpabuf_mhead_u8(req);
+		*categ = WLAN_ACTION_PROTECTED_DUAL;
+	}
 	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
 				     gas->wpa_s->own_addr, query->addr,
 				     wpabuf_head(req), wpabuf_len(req), 1000,
-				     NULL, 0);
+				     gas_query_tx_status, 0);
 	if (res == 0)
 		query->offchannel_tx_started = 1;
 	return res;
@@ -296,27 +402,41 @@
 
 
 /**
- * gas_query_rx - Indicate reception of a Public Action frame
+ * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
  * @gas: GAS query data from gas_query_init()
  * @da: Destination MAC address of the Action frame
  * @sa: Source MAC address of the Action frame
  * @bssid: BSSID of the Action frame
+ * @categ: Category of the Action frame
  * @data: Payload of the Action frame
  * @len: Length of @data
  * @freq: Frequency (in MHz) on which the frame was received
  * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
  */
 int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
-		 const u8 *bssid, const u8 *data, size_t len, int freq)
+		 const u8 *bssid, u8 categ, const u8 *data, size_t len,
+		 int freq)
 {
 	struct gas_query_pending *query;
 	u8 action, dialog_token, frag_id = 0, more_frags = 0;
 	u16 comeback_delay, resp_len;
 	const u8 *pos, *adv_proto;
+	int prot, pmf;
 
 	if (gas == NULL || len < 4)
 		return -1;
 
+	prot = categ == WLAN_ACTION_PROTECTED_DUAL;
+	pmf = pmf_in_use(gas->wpa_s, bssid);
+	if (prot && !pmf) {
+		wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
+		return 0;
+	}
+	if (!prot && pmf) {
+		wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
+		return 0;
+	}
+
 	pos = data;
 	action = *pos++;
 	dialog_token = *pos++;
@@ -426,8 +546,9 @@
 	struct gas_query *gas = eloop_data;
 	struct gas_query_pending *query = user_ctx;
 
-	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
-		   MAC2STR(query->addr));
+	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+		   " dialog token %u",
+		   MAC2STR(query->addr), query->dialog_token);
 	gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
 }
 
@@ -446,12 +567,47 @@
 }
 
 
+static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct gas_query_pending *query = work->ctx;
+	struct gas_query *gas = query->gas;
+
+	if (deinit) {
+		if (work->started) {
+			gas->work = NULL;
+			gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
+			return;
+		}
+
+		gas_query_free(query, 1);
+		return;
+	}
+
+	gas->work = work;
+
+	if (gas_query_tx(gas, query, query->req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		gas_query_free(query, 1);
+		return;
+	}
+	gas->current = query;
+
+	wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+		   query->dialog_token);
+	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+			       gas_query_timeout, gas, query);
+
+}
+
+
 /**
  * gas_query_req - Request a GAS query
  * @gas: GAS query data from gas_query_init()
  * @dst: Destination MAC address for the query
  * @freq: Frequency (in MHz) for the channel on which to send the query
- * @req: GAS query payload
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ *	return)
  * @cb: Callback function for reporting GAS query result and response
  * @ctx: Context pointer to use with the @cb call
  * Returns: dialog token (>= 0) on success or -1 on failure
@@ -485,28 +641,27 @@
 	if (query == NULL)
 		return -1;
 
+	query->gas = gas;
 	os_memcpy(query->addr, dst, ETH_ALEN);
 	query->dialog_token = dialog_token;
 	query->freq = freq;
 	query->cb = cb;
 	query->ctx = ctx;
+	query->req = req;
 	dl_list_add(&gas->pending, &query->list);
 
 	*(wpabuf_mhead_u8(req) + 2) = dialog_token;
 
-	wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
-		   " dialog_token %u", MAC2STR(dst), dialog_token);
-	if (gas_query_tx(gas, query, req) < 0) {
-		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
-			   MACSTR, MAC2STR(query->addr));
-		dl_list_del(&query->list);
-		os_free(query);
+	wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
+		" dialog_token=%u freq=%d",
+		MAC2STR(query->addr), query->dialog_token, query->freq);
+
+	if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
+			   query) < 0) {
+		gas_query_free(query, 1);
 		return -1;
 	}
 
-	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
-			       gas, query);
-
 	return dialog_token;
 }
 
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 5c3d161..ad13490 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -17,7 +17,8 @@
 struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
 void gas_query_deinit(struct gas_query *gas);
 int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
-		 const u8 *bssid, const u8 *data, size_t len, int freq);
+		 const u8 *bssid, u8 categ, const u8 *data, size_t len,
+		 int freq);
 
 /**
  * enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 4048cf7..5f30313 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -125,12 +125,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 47ef35e..3083dd8 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -590,7 +590,7 @@
 		peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
 		return ibss_rsn_auth_init(ibss_rsn, peer);
 	} else {
-		os_get_time(&peer->own_auth_tx);
+		os_get_reltime(&peer->own_auth_tx);
 		eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
 	}
 
@@ -834,9 +834,9 @@
 	if (peer &&
 	    peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
 		if (peer->own_auth_tx.sec) {
-			struct os_time now, diff;
-			os_get_time(&now);
-			os_time_sub(&now, &peer->own_auth_tx, &diff);
+			struct os_reltime now, diff;
+			os_get_reltime(&now);
+			os_reltime_sub(&now, &peer->own_auth_tx, &diff);
 			if (diff.sec == 0 && diff.usec < 500000) {
 				wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
 					   (int) diff.usec);
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 3089283..67fae2d 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -40,7 +40,7 @@
 	struct wpa_state_machine *auth;
 	int authentication_status;
 
-	struct os_time own_auth_tx;
+	struct os_reltime own_auth_tx;
 };
 
 struct ibss_rsn {
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 36f75a1..da8971d 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1,6 +1,7 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,6 +19,8 @@
 #include "eap_common/eap_defs.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "config_ssid.h"
@@ -112,6 +115,8 @@
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		if (cred->roaming_consortium_len)
 			return 1;
+		if (cred->required_roaming_consortium_len)
+			return 1;
 	}
 	return 0;
 }
@@ -242,6 +247,7 @@
 			    interworking_anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
 				       NULL);
@@ -249,7 +255,6 @@
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -516,12 +521,13 @@
 	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
 		return 0; /* method not supported */
 
-	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
+	    eap->method != EAP_TYPE_FAST) {
 		/* Only tunneled methods with username/password supported */
 		return 0;
 	}
 
-	if (eap->method == EAP_TYPE_PEAP) {
+	if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
 		if (eap->inner_method &&
 		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
 			return 0;
@@ -747,6 +753,59 @@
 #endif /* INTERWORKING_3GPP */
 
 
+static int already_connected(struct wpa_supplicant *wpa_s,
+			     struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
+		return 0;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid->parent_cred != cred)
+		return 0;
+
+	if (ssid->ssid_len != bss->ssid_len ||
+	    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+		return 0;
+
+	return 1;
+}
+
+
+static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
+				     struct wpa_cred *cred,
+				     struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->parent_cred != cred)
+			continue;
+		if (ssid->ssid_len != bss->ssid_len ||
+		    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+			continue;
+
+		break;
+	}
+
+	if (ssid == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
+
+	if (ssid == wpa_s->current_ssid) {
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+}
+
+
 static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
 					struct wpa_ssid *ssid)
 {
@@ -768,7 +827,6 @@
 {
 #ifdef INTERWORKING_3GPP
 	struct wpa_ssid *ssid;
-	const u8 *ie;
 	int eap_type;
 	int res;
 	char prefix;
@@ -776,12 +834,17 @@
 	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
 		return -1;
 
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie == NULL)
-		return -1;
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
 		   MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
@@ -791,11 +854,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ie + 2, ie[1]);
-	ssid->ssid_len = ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -944,6 +1007,27 @@
 }
 
 
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	const u8 *ie;
+
+	if (cred->required_roaming_consortium_len == 0)
+		return 0;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+	if (ie == NULL &&
+	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+		return 1;
+
+	return !roaming_consortium_match(ie,
+					 bss->anqp ?
+					 bss->anqp->roaming_consortium : NULL,
+					 cred->required_roaming_consortium,
+					 cred->required_roaming_consortium_len);
+}
+
+
 static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
 {
 	size_t i;
@@ -991,6 +1075,8 @@
 
 		if (cred_excluded_ssid(cred, bss))
 			continue;
+		if (cred_no_required_oi_match(cred, bss))
+			continue;
 
 		if (selected == NULL ||
 		    selected->priority < cred->priority)
@@ -1100,19 +1186,32 @@
 	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
 		return -1;
 
+	if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+	    wpa_config_set_quoted(ssid, "domain_suffix_match",
+				  cred->domain_suffix_match) < 0)
+		return -1;
+
 	return 0;
 }
 
 
 static int interworking_connect_roaming_consortium(
 	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
-	struct wpa_bss *bss, const u8 *ssid_ie)
+	struct wpa_bss *bss)
 {
 	struct wpa_ssid *ssid;
 
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
 		   "roaming consortium match", MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL)
 		return -1;
@@ -1121,11 +1220,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
-	ssid->ssid_len = ssid_ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -1162,13 +1261,12 @@
 	struct nai_realm_eap *eap = NULL;
 	u16 count, i;
 	char buf[100];
-	const u8 *ie;
 
 	if (wpa_s->conf->cred == NULL || bss == NULL)
 		return -1;
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie == NULL || ie[1] == 0) {
-		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+	if (disallowed_bssid(wpa_s, bss->bssid) ||
+	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
 			   MACSTR, MAC2STR(bss->bssid));
 		return -1;
 	}
@@ -1208,7 +1306,7 @@
 	    (cred == NULL || cred_rc->priority >= cred->priority) &&
 	    (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
 		return interworking_connect_roaming_consortium(wpa_s, cred_rc,
-							       bss, ie);
+							       bss);
 
 	if (cred_3gpp &&
 	    (cred == NULL || cred_3gpp->priority >= cred->priority)) {
@@ -1248,6 +1346,15 @@
 	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
 		   MAC2STR(bss->bssid));
 
+	if (already_connected(wpa_s, cred, bss)) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+			MAC2STR(bss->bssid));
+		nai_realm_free(realm, count);
+		return 0;
+	}
+
+	remove_duplicate_network(wpa_s, cred, bss);
+
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
 		nai_realm_free(realm, count);
@@ -1258,11 +1365,11 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
-	ssid->ssid = os_zalloc(ie[1] + 1);
+	ssid->ssid = os_zalloc(bss->ssid_len + 1);
 	if (ssid->ssid == NULL)
 		goto fail;
-	os_memcpy(ssid->ssid, ie + 2, ie[1]);
-	ssid->ssid_len = ie[1];
+	os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+	ssid->ssid_len = bss->ssid_len;
 
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
@@ -1311,6 +1418,13 @@
 		}
 		break;
 	case EAP_TYPE_PEAP:
+	case EAP_TYPE_FAST:
+		if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"",
+				   0) < 0)
+			goto fail;
+		if (wpa_config_set(ssid, "pac_file",
+				   "\"blob://pac_interworking\"", 0) < 0)
+			goto fail;
 		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
 			    eap_get_name(EAP_VENDOR_IETF,
 					 eap->inner_method ?
@@ -1353,6 +1467,23 @@
 	if (bss->anqp == NULL || 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_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+							     wpa_s->imsi,
+							     &len);
+		if (wpa_s->mnc_len > 0) {
+			wpa_s->imsi[len] = '\0';
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+				   wpa_s->imsi, wpa_s->mnc_len);
+		} else {
+			wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+		}
+	}
+#endif /* CONFIG_EAP_PROXY */
+
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
 		char *sep;
 		const char *imsi;
@@ -1377,7 +1508,8 @@
 #endif /* CONFIG_EAP_PROXY */
 
 		if (cred->imsi == NULL || !cred->imsi[0] ||
-		    cred->milenage == NULL || !cred->milenage[0])
+		    (!wpa_s->conf->external_sim &&
+		     (cred->milenage == NULL || !cred->milenage[0])))
 			continue;
 
 		sep = os_strchr(cred->imsi, '-');
@@ -1404,6 +1536,8 @@
 		if (ret) {
 			if (cred_excluded_ssid(cred, bss))
 				continue;
+			if (cred_no_required_oi_match(cred, bss))
+				continue;
 			if (selected == NULL ||
 			    selected->priority < cred->priority)
 				selected = cred;
@@ -1446,6 +1580,8 @@
 			if (nai_realm_find_eap(cred, &realm[i])) {
 				if (cred_excluded_ssid(cred, bss))
 					continue;
+				if (cred_no_required_oi_match(cred, bss))
+					continue;
 				if (selected == NULL ||
 				    selected->priority < cred->priority)
 					selected = cred;
@@ -1465,6 +1601,13 @@
 {
 	struct wpa_cred *cred, *cred2;
 
+	if (disallowed_bssid(wpa_s, bss->bssid) ||
+	    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
+			   MACSTR, MAC2STR(bss->bssid));
+		return NULL;
+	}
+
 	cred = interworking_credentials_available_realm(wpa_s, bss);
 	cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
 	if (cred && cred2 && cred2->priority >= cred->priority)
@@ -1514,6 +1657,8 @@
 			      struct wpa_cred *cred,
 			      struct wpabuf *domain_names)
 {
+	size_t i;
+	int ret = -1;
 #ifdef INTERWORKING_3GPP
 	char nai[100], *realm;
 
@@ -1528,6 +1673,12 @@
 		mnc_len = wpa_s->mnc_len;
 	}
 #endif /* CONFIG_PCSC */
+#ifdef CONFIG_EAP_PROXY
+	else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+		imsi = wpa_s->imsi;
+		mnc_len = wpa_s->mnc_len;
+	}
+#endif /* CONFIG_EAP_PROXY */
 	if (domain_names &&
 	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
 		realm = os_strchr(nai, '@');
@@ -1538,16 +1689,20 @@
 		if (realm &&
 		    domain_name_list_contains(domain_names, realm))
 			return 1;
+		if (realm)
+			ret = 0;
 	}
 #endif /* INTERWORKING_3GPP */
 
 	if (domain_names == NULL || cred->domain == NULL)
-		return 0;
+		return ret;
 
-	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
-		   "home SP FQDN %s", cred->domain);
-	if (domain_name_list_contains(domain_names, cred->domain))
-		return 1;
+	for (i = 0; i < cred->num_domain; i++) {
+		wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+			   "home SP FQDN %s", cred->domain[i]);
+		if (domain_name_list_contains(domain_names, cred->domain[i]))
+			return 1;
+	}
 
 	return 0;
 }
@@ -1739,6 +1894,9 @@
 		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
 		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
 			continue; /* AP does not support Interworking */
+		if (disallowed_bssid(wpa_s, bss->bssid) ||
+		    disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
+			continue; /* Disallowed BSS */
 
 		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
 			if (bss->anqp == NULL) {
@@ -1833,12 +1991,12 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
 
@@ -2045,7 +2203,8 @@
 }
 
 
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+			int *freqs)
 {
 	interworking_stop_fetch_anqp(wpa_s);
 	wpa_s->network_select = 1;
@@ -2055,7 +2214,12 @@
 	wpa_printf(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;
+	os_free(wpa_s->manual_scan_freqs);
+	wpa_s->manual_scan_freqs = freqs;
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
 	return 0;
@@ -2068,6 +2232,7 @@
 			const struct wpabuf *resp, u16 status_code)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	struct wpabuf *n;
 
 	wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
 		" dialog_token=%d status_code=%d resp_len=%d",
@@ -2076,10 +2241,14 @@
 	if (!resp)
 		return;
 
-	wpabuf_free(wpa_s->last_gas_resp);
-	wpa_s->last_gas_resp = wpabuf_dup(resp);
-	if (wpa_s->last_gas_resp == NULL)
+	n = wpabuf_dup(resp);
+	if (n == NULL)
 		return;
+	wpabuf_free(wpa_s->prev_gas_resp);
+	wpa_s->prev_gas_resp = wpa_s->last_gas_resp;
+	os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN);
+	wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token;
+	wpa_s->last_gas_resp = n;
 	os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
 	wpa_s->last_gas_dialog_token = dialog_token;
 }
@@ -2133,11 +2302,11 @@
 	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+		wpabuf_free(buf);
 		ret = -1;
 	} else
 		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
 			   "%u", res);
 
-	wpabuf_free(buf);
 	return ret;
 }
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 4a4af82..c8e7093 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -22,7 +22,8 @@
 		     const struct wpabuf *query);
 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+			int *freqs);
 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
 int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 39b837e..d56935d 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -16,21 +16,30 @@
 #include "driver_i.h"
 #include "p2p_supplicant.h"
 
-extern struct wpa_driver_ops *wpa_drivers[];
-
 
 static void usage(void)
 {
 	int i;
 	printf("%s\n\n%s\n"
 	       "usage:\n"
-	       "  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+	       "  wpa_supplicant [-BddhKLqq"
+#ifdef CONFIG_DEBUG_SYSLOG
+	       "s"
+#endif /* CONFIG_DEBUG_SYSLOG */
+	       "t"
+#ifdef CONFIG_DBUS
+	       "u"
+#endif /* CONFIG_DBUS */
+	       "vW] [-P<pid file>] "
 	       "[-g<global ctrl>] \\\n"
 	       "        [-G<group>] \\\n"
 	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
 	       "[-p<driver_param>] \\\n"
-	       "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
-	       "\\\n"
+	       "        [-b<br_ifname>] [-e<entropy file>]"
+#ifdef CONFIG_DEBUG_FILE
+	       " [-f<debug file>]"
+#endif /* CONFIG_DEBUG_FILE */
+	       " \\\n"
 	       "        [-o<override driver>] [-O<override ctrl>] \\\n"
 	       "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
 	       "[-D<driver>] \\\n"
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ab62bea..a82fbf3 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -96,7 +96,7 @@
 		     MAC2STR(wpa_s->bssid),
 		     wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
 		     wpa_ssid_txt(wpa_s->current_ssid->ssid,
-		     wpa_s->current_ssid->ssid_len): "");
+				  wpa_s->current_ssid->ssid_len) : "");
 #endif /* ANDROID */
 }
 
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index d94407c..40cbea1 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -159,6 +159,21 @@
 		return;
 	}
 
+	/* Accept report only if the contents of the frame matches */
+	if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
+	    os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
+		      wpabuf_len(wpa_s->pending_action_tx)) != 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+				   "mismatching contents with pending frame");
+		wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
+			    data, data_len);
+		wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+				wpa_s->pending_action_tx);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
+
 	wpabuf_free(wpa_s->pending_action_tx);
 	wpa_s->pending_action_tx = NULL;
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index d7b3189..fa75fa5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1,6 +1,7 @@
 /*
  * wpa_supplicant - P2P
  * 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.
@@ -19,6 +20,7 @@
 #include "ap/ap_config.h"
 #include "ap/sta_info.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/wps_hostapd.h"
 #include "ap/p2p_hostapd.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
@@ -33,6 +35,7 @@
 #include "offchannel.h"
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
+#include "wifi_display.h"
 
 
 /*
@@ -48,11 +51,7 @@
  * How many seconds to try to reconnect to the GO when connection in P2P client
  * role has been lost.
  */
-#ifdef ANDROID_P2P
-#define P2P_MAX_CLIENT_IDLE 20
-#else
 #define P2P_MAX_CLIENT_IDLE 10
-#endif /* ANDROID_P2P */
 #endif /* P2P_MAX_CLIENT_IDLE */
 
 #ifndef P2P_MAX_INITIAL_CONN_WAIT
@@ -73,6 +72,15 @@
 #define P2P_MAX_INITIAL_CONN_WAIT_GO 10
 #endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
 
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
 #ifndef P2P_CONCURRENT_SEARCH_DELAY
 #define P2P_CONCURRENT_SEARCH_DELAY 500
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -88,9 +96,7 @@
 	P2P_GROUP_REMOVAL_UNAVAILABLE,
 	P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
 	P2P_GROUP_REMOVAL_PSK_FAILURE,
-#ifdef ANDROID_P2P
 	P2P_GROUP_REMOVAL_FREQ_CONFLICT
-#endif
 };
 
 
@@ -98,24 +104,26 @@
 static struct wpa_supplicant *
 wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
 			 int go);
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+			       const u8 *ssid, size_t ssid_len);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+				   const u8 *ssid, size_t ssid_len);
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 			 const u8 *dev_addr, enum p2p_wps_method wps_method,
-			 int auto_join);
+			 int auto_join, int freq,
+			 const u8 *ssid, size_t ssid_len);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 					     void *timeout_ctx);
-#ifdef ANDROID_P2P
 static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
-#endif
 static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
 					int group_added);
 static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_stop_listen(void *ctx);
 
 
 /*
@@ -125,7 +133,7 @@
 static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
 {
 	int *freqs;
-	int num;
+	int num, unused;
 
 	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
 	if (!freqs)
@@ -135,7 +143,9 @@
 				     wpa_s->num_multichan_concurrent);
 	os_free(freqs);
 
-	return wpa_s->num_multichan_concurrent - num;
+	unused = wpa_s->num_multichan_concurrent - num;
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused);
+	return unused;
 }
 
 
@@ -165,6 +175,8 @@
 
 	os_free(freqs);
 
+	dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+
 	return j;
 }
 
@@ -174,10 +186,13 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
-	    wpas_p2p_num_unused_channels(wpa_s) > 0 &&
-	    wpa_s->parent->conf->p2p_ignore_shared_freq)
+	if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+	    freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
+			   freq);
 		freq = 0;
+	}
 	p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
 }
 
@@ -187,6 +202,12 @@
 {
 	size_t i;
 
+	if (wpa_s->p2p_scan_work) {
+		struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+		wpa_s->p2p_scan_work = NULL;
+		radio_work_done(work);
+	}
+
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 
@@ -195,14 +216,29 @@
 
 	for (i = 0; i < scan_res->num; i++) {
 		struct wpa_scan_res *bss = scan_res->res[i];
-		struct os_time time_tmp_age, entry_ts;
+		struct os_reltime time_tmp_age, entry_ts;
+		const u8 *ies;
+		size_t ies_len;
+
 		time_tmp_age.sec = bss->age / 1000;
 		time_tmp_age.usec = (bss->age % 1000) * 1000;
-		os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+		os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+
+		ies = (const u8 *) (bss + 1);
+		ies_len = bss->ie_len;
+		if (bss->beacon_ie_len > 0 &&
+		    !wpa_scan_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+		    wpa_scan_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+			wpa_printf(MSG_DEBUG, "P2P: Use P2P IE(s) from Beacon frame since no P2P IE(s) in Probe Response frames received for "
+				   MACSTR, MAC2STR(bss->bssid));
+			ies = ies + ies_len;
+			ies_len = bss->beacon_ie_len;
+		}
+
+
 		if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
 					 bss->freq, &entry_ts, bss->level,
-					 (const u8 *) (bss + 1),
-					 bss->ie_len) > 0)
+					 ies, ies_len) > 0)
 			break;
 	}
 
@@ -210,94 +246,130 @@
 }
 
 
+static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct wpa_driver_scan_params *params = work->ctx;
+	int ret;
+
+	if (deinit) {
+		if (!work->started) {
+			wpa_scan_free_params(params);
+			return;
+		}
+
+		wpa_s->p2p_scan_work = NULL;
+		return;
+	}
+
+	ret = wpa_drv_scan(wpa_s, params);
+	wpa_scan_free_params(params);
+	work->ctx = NULL;
+	if (ret) {
+		radio_work_done(work);
+		return;
+	}
+
+	os_get_reltime(&wpa_s->scan_trigger_time);
+	wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+	wpa_s->own_scan_requested = 1;
+	wpa_s->p2p_scan_work = work;
+}
+
+
 static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 			 unsigned int num_req_dev_types,
 			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	struct wpa_supplicant *ifs;
-	struct wpa_driver_scan_params params;
-	int ret;
+	struct wpa_driver_scan_params *params = NULL;
 	struct wpabuf *wps_ie, *ies;
-	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
 	size_t ielen;
+	u8 *n;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs->sta_scan_pending &&
-		    (wpas_scan_scheduled(ifs) || ifs->scanning) &&
-		    wpas_p2p_in_progress(wpa_s) == 2) {
-			wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
-				   "pending station mode scan to be "
-				   "completed on interface %s", ifs->ifname);
-			wpa_s->global->p2p_cb_on_scan_complete = 1;
-			wpa_supplicant_req_scan(ifs, 0, 0);
-			return 1;
-		}
+	if (wpa_s->p2p_scan_work) {
+		wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending");
+		return -1;
 	}
 
-	os_memset(&params, 0, sizeof(params));
+	params = os_zalloc(sizeof(*params));
+	if (params == NULL)
+		return -1;
 
 	/* P2P Wildcard SSID */
-	params.num_ssids = 1;
-	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
-	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+	params->num_ssids = 1;
+	n = os_malloc(P2P_WILDCARD_SSID_LEN);
+	if (n == NULL)
+		goto fail;
+	os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+	params->ssids[0].ssid = n;
+	params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
 	wpa_s->wps->dev.p2p = 1;
 	wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
 					wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
 					num_req_dev_types, req_dev_types);
 	if (wps_ie == NULL)
-		return -1;
+		goto fail;
 
 	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
 	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
 	if (ies == NULL) {
 		wpabuf_free(wps_ie);
-		return -1;
+		goto fail;
 	}
 	wpabuf_put_buf(ies, wps_ie);
 	wpabuf_free(wps_ie);
 
 	p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
 
-	params.p2p_probe = 1;
-	params.extra_ies = wpabuf_head(ies);
-	params.extra_ies_len = wpabuf_len(ies);
+	params->p2p_probe = 1;
+	n = os_malloc(wpabuf_len(ies));
+	if (n == NULL) {
+		wpabuf_free(ies);
+		goto fail;
+	}
+	os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
+	params->extra_ies = n;
+	params->extra_ies_len = wpabuf_len(ies);
+	wpabuf_free(ies);
 
 	switch (type) {
 	case P2P_SCAN_SOCIAL:
-		params.freqs = social_channels;
+		params->freqs = os_malloc(4 * sizeof(int));
+		if (params->freqs == NULL)
+			goto fail;
+		params->freqs[0] = 2412;
+		params->freqs[1] = 2437;
+		params->freqs[2] = 2462;
+		params->freqs[3] = 0;
 		break;
 	case P2P_SCAN_FULL:
 		break;
 	case P2P_SCAN_SOCIAL_PLUS_ONE:
-		social_channels[3] = freq;
-		params.freqs = social_channels;
+		params->freqs = os_malloc(5 * sizeof(int));
+		if (params->freqs == NULL)
+			goto fail;
+		params->freqs[0] = 2412;
+		params->freqs[1] = 2437;
+		params->freqs[2] = 2462;
+		params->freqs[3] = freq;
+		params->freqs[4] = 0;
 		break;
 	}
 
-	ret = wpa_drv_scan(wpa_s, &params);
+	radio_remove_works(wpa_s, "p2p-scan", 0);
+	if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
+			   params) < 0)
+		goto fail;
+	return 0;
 
-	wpabuf_free(ies);
-
-	if (ret) {
-		for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-			if (ifs->scanning ||
-			    ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
-				wpa_s->global->p2p_cb_on_scan_complete = 1;
-				ret = 1;
-				break;
-			}
-		}
-	} else {
-		os_get_time(&wpa_s->scan_trigger_time);
-		wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
-	}
-
-	return ret;
+fail:
+	wpa_scan_free_params(params);
+	return -1;
 }
 
 
@@ -405,11 +477,9 @@
 	case P2P_GROUP_REMOVAL_PSK_FAILURE:
 		reason = " reason=PSK_FAILURE";
 		break;
-#ifdef ANDROID_P2P
 	case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
 		reason = " reason=FREQ_CONFLICT";
 		break;
-#endif
 	default:
 		reason = "";
 		break;
@@ -420,9 +490,8 @@
 			       wpa_s->ifname, gtype, reason);
 	}
 
-#ifdef ANDROID_P2P
-	eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
-#endif
+	if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout");
 	if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
 		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
 	if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
@@ -432,6 +501,12 @@
 		wpa_s->p2p_in_provisioning = 0;
 	}
 
+	/*
+	 * Make sure wait for the first client does not remain active after the
+	 * group has been removed.
+	 */
+	wpa_s->global->p2p_go_wait_client.sec = 0;
+
 	if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
 		wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
@@ -452,6 +527,17 @@
 		return 1;
 	}
 
+	if (!wpa_s->p2p_go_group_formation_completed) {
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
+
+	wpa_s->show_group_started = 0;
+	os_free(wpa_s->go_params);
+	wpa_s->go_params = NULL;
+
+	wpa_s->waiting_presence_resp = 0;
+
 	wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
 	if (ssid && (ssid->p2p_group ||
 		     ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
@@ -474,7 +560,6 @@
 		wpa_config_remove_network(wpa_s->conf, id);
 		wpa_supplicant_clear_status(wpa_s);
 		wpa_supplicant_cancel_sched_scan(wpa_s);
-		wpa_s->sta_scan_pending = 0;
 	} else {
 		wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
 			   "found");
@@ -504,6 +589,10 @@
 		bssid = wpa_s->bssid;
 
 	bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+	if (bss == NULL && wpa_s->go_params &&
+	    !is_zero_ether_addr(wpa_s->go_params->peer_device_addr))
+		bss = wpa_bss_get_p2p_dev_addr(
+			wpa_s, wpa_s->go_params->peer_device_addr);
 	if (bss == NULL) {
 		u8 iface_addr[ETH_ALEN];
 		if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
@@ -518,6 +607,9 @@
 	}
 
 	p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+	if (p2p == NULL)
+		p2p = wpa_bss_get_vendor_ie_multi_beacon(bss,
+							 P2P_IE_VENDOR_TYPE);
 	if (p2p == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
 			   "group is persistent - BSS " MACSTR
@@ -728,8 +820,10 @@
 	 */
 	if (wpa_s->global->p2p_group_formation)
 		wpa_s = wpa_s->global->p2p_group_formation;
-	wpa_s->global->p2p_group_formation = NULL;
-	wpa_s->p2p_in_provisioning = 0;
+	if (wpa_s->p2p_go_group_formation_completed) {
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
 
 	if (!success) {
 		wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -777,13 +871,6 @@
 		 * packets.
 		 */
 		wpa_s->show_group_started = 1;
-#ifdef ANDROID_P2P
-		/* For client Second phase of Group formation (4-way handshake) can be still pending
-		 * So we need to restore wpa_s->global->p2p_group_formation */
-		wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
-		wpa_s->global->p2p_group_formation = wpa_s;
-#endif
-
 	} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
@@ -819,11 +906,37 @@
 		network_id = ssid->id;
 	if (!client) {
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
-		os_get_time(&wpa_s->global->p2p_go_wait_client);
+		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 	}
 }
 
 
+struct send_action_work {
+	unsigned int freq;
+	u8 dst[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+	size_t len;
+	unsigned int wait_time;
+	u8 buf[0];
+};
+
+
+static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
+					      void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (!wpa_s->p2p_send_action_work)
+		return;
+
+	wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out");
+	os_free(wpa_s->p2p_send_action_work->ctx);
+	radio_work_done(wpa_s->p2p_send_action_work);
+	wpa_s->p2p_send_action_work = NULL;
+}
+
+
 static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
 					   unsigned int freq,
 					   const u8 *dst, const u8 *src,
@@ -834,10 +947,31 @@
 {
 	enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
 
+	if (wpa_s->p2p_send_action_work) {
+		struct send_action_work *awork;
+		awork = wpa_s->p2p_send_action_work->ctx;
+		if (awork->wait_time == 0) {
+			os_free(awork);
+			radio_work_done(wpa_s->p2p_send_action_work);
+			wpa_s->p2p_send_action_work = NULL;
+		} else {
+			/*
+			 * In theory, this should not be needed, but number of
+			 * places in the P2P code is still using non-zero wait
+			 * time for the last Action frame in the sequence and
+			 * some of these do not call send_action_done().
+			 */
+			eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+					     wpa_s, NULL);
+			eloop_register_timeout(
+				0, awork->wait_time * 1000,
+				wpas_p2p_send_action_work_timeout,
+				wpa_s, NULL);
+		}
+	}
+
 	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
 		return;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return;
 
 	switch (result) {
 	case OFFCHANNEL_SEND_ACTION_SUCCESS:
@@ -867,11 +1001,87 @@
 }
 
 
+static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct send_action_work *awork = work->ctx;
+
+	if (deinit) {
+		if (work->started) {
+			eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+					     wpa_s, NULL);
+			wpa_s->p2p_send_action_work = NULL;
+			offchannel_send_action_done(wpa_s);
+		}
+		os_free(awork);
+		return;
+	}
+
+	if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src,
+				   awork->bssid, awork->buf, awork->len,
+				   awork->wait_time,
+				   wpas_p2p_send_action_tx_status, 1) < 0) {
+		os_free(awork);
+		radio_work_done(work);
+		return;
+	}
+	wpa_s->p2p_send_action_work = work;
+}
+
+
+static int wpas_send_action_work(struct wpa_supplicant *wpa_s,
+				 unsigned int freq, const u8 *dst,
+				 const u8 *src, const u8 *bssid, const u8 *buf,
+				 size_t len, unsigned int wait_time)
+{
+	struct send_action_work *awork;
+
+	if (wpa_s->p2p_send_action_work) {
+		wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
+		return -1;
+	}
+
+	awork = os_zalloc(sizeof(*awork) + len);
+	if (awork == NULL)
+		return -1;
+
+	awork->freq = freq;
+	os_memcpy(awork->dst, dst, ETH_ALEN);
+	os_memcpy(awork->src, src, ETH_ALEN);
+	os_memcpy(awork->bssid, bssid, ETH_ALEN);
+	awork->len = len;
+	awork->wait_time = wait_time;
+	os_memcpy(awork->buf, buf, len);
+
+	if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+			   wpas_send_action_cb, awork) < 0) {
+		os_free(awork);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static int wpas_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)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	int listen_freq = -1, send_freq = -1;
+
+	if (wpa_s->p2p_listen_work)
+		listen_freq = wpa_s->p2p_listen_work->freq;
+	if (wpa_s->p2p_send_action_work)
+		send_freq = wpa_s->p2p_send_action_work->freq;
+	if (listen_freq != (int) freq && send_freq != (int) freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)",
+			   listen_freq, send_freq);
+		return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+					     len, wait_time);
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
 	return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
 				      wait_time,
 				      wpas_p2p_send_action_tx_status, 1);
@@ -881,6 +1091,15 @@
 static void wpas_send_action_done(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+
+	if (wpa_s->p2p_send_action_work) {
+		eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+				     wpa_s, NULL);
+		os_free(wpa_s->p2p_send_action_work->ctx);
+		radio_work_done(wpa_s->p2p_send_action_work);
+		wpa_s->p2p_send_action_work = NULL;
+	}
+
 	offchannel_send_action_done(wpa_s);
 }
 
@@ -901,15 +1120,29 @@
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 				    struct p2p_go_neg_results *res)
 {
-	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
-		   MAC2STR(res->peer_interface_addr));
+	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
+		   " dev_addr " MACSTR " wps_method %d",
+		   MAC2STR(res->peer_interface_addr),
+		   MAC2STR(res->peer_device_addr), res->wps_method);
 	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
 			  res->ssid, res->ssid_len);
 	wpa_supplicant_ap_deinit(wpa_s);
 	wpas_copy_go_neg_results(wpa_s, res);
-	if (res->wps_method == WPS_PBC)
+	if (res->wps_method == WPS_PBC) {
 		wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
-	else {
+#ifdef CONFIG_WPS_NFC
+	} else if (res->wps_method == WPS_NFC) {
+		wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
+				   res->peer_interface_addr,
+				   wpa_s->parent->p2p_oob_dev_pw,
+				   wpa_s->parent->p2p_oob_dev_pw_id, 1,
+				   wpa_s->parent->p2p_oob_dev_pw_id ==
+				   DEV_PW_NFC_CONNECTION_HANDOVER ?
+				   wpa_s->parent->p2p_peer_oob_pubkey_hash :
+				   NULL,
+				   NULL, 0, 0);
+#endif /* CONFIG_WPS_NFC */
+	} else {
 		u16 dev_pw_id = DEV_PW_DEFAULT;
 		if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
 			dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
@@ -996,6 +1229,7 @@
 				       " [PERSISTENT]" : "");
 		}
 
+		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 		if (params->persistent_group) {
 			network_id = wpas_p2p_store_persistent_group(
 				wpa_s->parent, ssid,
@@ -1007,6 +1241,21 @@
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
+
+		if (wpa_s->p2p_first_connection_timeout) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P: Start group formation timeout of %d seconds until first data connection on GO",
+				wpa_s->p2p_first_connection_timeout);
+			wpa_s->p2p_go_group_formation_completed = 0;
+			wpa_s->global->p2p_group_formation = wpa_s;
+			eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+					     wpa_s->parent, NULL);
+			eloop_register_timeout(
+				wpa_s->p2p_first_connection_timeout, 0,
+				wpas_p2p_group_formation_timeout,
+				wpa_s->parent, NULL);
+		}
+
 		return;
 	}
 
@@ -1017,10 +1266,24 @@
 			   "filtering");
 		return;
 	}
-	if (params->wps_method == WPS_PBC)
+	if (params->wps_method == WPS_PBC) {
 		wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
 					  params->peer_device_addr);
-	else if (wpa_s->p2p_pin[0])
+#ifdef CONFIG_WPS_NFC
+	} else if (params->wps_method == WPS_NFC) {
+		if (wpa_s->parent->p2p_oob_dev_pw_id !=
+		    DEV_PW_NFC_CONNECTION_HANDOVER &&
+		    !wpa_s->parent->p2p_oob_dev_pw) {
+			wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+			return;
+		}
+		wpas_ap_wps_add_nfc_pw(
+			wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+			wpa_s->parent->p2p_oob_dev_pw,
+			wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+			wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+#endif /* CONFIG_WPS_NFC */
+	} else if (wpa_s->p2p_pin[0])
 		wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
 					  wpa_s->p2p_pin, NULL, 0, 0);
 	os_free(wpa_s->go_params);
@@ -1057,6 +1320,7 @@
 		WPAS_MODE_P2P_GO;
 	ssid->frequency = params->freq;
 	ssid->ht40 = params->ht40;
+	ssid->vht = params->vht;
 	ssid->ssid = os_zalloc(params->ssid_len + 1);
 	if (ssid->ssid) {
 		os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1125,7 +1389,14 @@
 	d->pbc_in_m1 = s->pbc_in_m1;
 	d->ignore_old_scan_res = s->ignore_old_scan_res;
 	d->beacon_int = s->beacon_int;
+	d->dtim_period = s->dtim_period;
 	d->disassoc_low_ack = s->disassoc_low_ack;
+	d->disable_scan_offload = s->disable_scan_offload;
+
+	if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+		d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
+		d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
+	}
 }
 
 
@@ -1143,8 +1414,7 @@
 	if (os_strlen(ifname) >= IFNAMSIZ &&
 	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
 		/* Try to avoid going over the IFNAMSIZ length limit */
-		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
-			    wpa_s->p2p_group_idx);
+		os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
 	}
 }
 
@@ -1277,12 +1547,21 @@
 			     wpa_s->parent, NULL);
 	if (wpa_s->global->p2p)
 		p2p_group_formation_failed(wpa_s->global->p2p);
-	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		wpa_drv_p2p_group_formation_failed(wpa_s);
 	wpas_group_formation_completed(wpa_s, 0);
 }
 
 
+static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure");
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+			     wpa_s->parent, NULL);
+	eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+			       wpa_s->parent, NULL);
+	wpa_s->global->p2p_fail_on_wps_complete = 0;
+}
+
+
 void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->global->p2p_group_formation != wpa_s)
@@ -1295,7 +1574,7 @@
 }
 
 
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
@@ -1316,6 +1595,8 @@
 
 	if (wpa_s->p2p_go_ht40)
 		res->ht40 = 1;
+	if (wpa_s->p2p_go_vht)
+		res->vht = 1;
 
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
 		       "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -1380,7 +1661,7 @@
 }
 
 
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
@@ -1390,23 +1671,20 @@
 }
 
 
-void wpas_dev_found(void *ctx, const u8 *addr,
-		    const struct p2p_peer_info *info,
-		    int new_device)
+static void wpas_dev_found(void *ctx, const u8 *addr,
+			   const struct p2p_peer_info *info,
+			   int new_device)
 {
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
-#define WFD_DEV_INFO_SIZE 9
-	char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
-	os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
+	char *wfd_dev_info_hex = NULL;
+
 #ifdef CONFIG_WIFI_DISPLAY
-	if (info->wfd_subelems) {
-		wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
-					wpabuf_head(info->wfd_subelems),
-					WFD_DEV_INFO_SIZE);
-	}
+	wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+						    WFD_SUBELEM_DEVICE_INFO);
 #endif /* CONFIG_WIFI_DISPLAY */
+
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
 		       " p2p_dev_addr=" MACSTR
 		       " pri_dev_type=%s name='%s' config_methods=0x%x "
@@ -1416,7 +1694,10 @@
 					    sizeof(devtype)),
 		       info->device_name, info->config_methods,
 		       info->dev_capab, info->group_capab,
-		       wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
+		       wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+		       wfd_dev_info_hex ? wfd_dev_info_hex : "");
+
+	os_free(wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
@@ -1441,32 +1722,108 @@
 }
 
 
+struct wpas_p2p_listen_work {
+	unsigned int freq;
+	unsigned int duration;
+	struct wpabuf *probe_resp_ie;
+};
+
+
+static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork)
+{
+	if (lwork == NULL)
+		return;
+	wpabuf_free(lwork->probe_resp_ie);
+	os_free(lwork);
+}
+
+
+static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_p2p_listen_work *lwork;
+
+	if (!wpa_s->p2p_listen_work)
+		return;
+
+	lwork = wpa_s->p2p_listen_work->ctx;
+	wpas_p2p_listen_work_free(lwork);
+	radio_work_done(wpa_s->p2p_listen_work);
+	wpa_s->p2p_listen_work = NULL;
+}
+
+
+static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct wpas_p2p_listen_work *lwork = work->ctx;
+
+	if (deinit) {
+		if (work->started) {
+			wpa_s->p2p_listen_work = NULL;
+			wpas_stop_listen(wpa_s);
+		}
+		wpas_p2p_listen_work_free(lwork);
+		return;
+	}
+
+	wpa_s->p2p_listen_work = work;
+
+	wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL);
+
+	if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
+			   "report received Probe Request frames");
+		wpas_p2p_listen_work_done(wpa_s);
+		return;
+	}
+
+	wpa_s->pending_listen_freq = lwork->freq;
+	wpa_s->pending_listen_duration = lwork->duration;
+
+	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
+	{
+		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
+			   "to remain on channel (%u MHz) for Listen "
+			   "state", lwork->freq);
+		wpas_p2p_listen_work_done(wpa_s);
+		wpa_s->pending_listen_freq = 0;
+		return;
+	}
+	wpa_s->off_channel_freq = 0;
+	wpa_s->roc_waiting_drv_freq = lwork->freq;
+}
+
+
 static int wpas_start_listen(void *ctx, unsigned int freq,
 			     unsigned int duration,
 			     const struct wpabuf *probe_resp_ie)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	struct wpas_p2p_listen_work *lwork;
 
-	wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
-
-	if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
-			   "report received Probe Request frames");
+	if (wpa_s->p2p_listen_work) {
+		wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists");
 		return -1;
 	}
 
-	wpa_s->pending_listen_freq = freq;
-	wpa_s->pending_listen_duration = duration;
+	lwork = os_zalloc(sizeof(*lwork));
+	if (lwork == NULL)
+		return -1;
+	lwork->freq = freq;
+	lwork->duration = duration;
+	if (probe_resp_ie) {
+		lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie);
+		if (lwork->probe_resp_ie == NULL) {
+			wpas_p2p_listen_work_free(lwork);
+			return -1;
+		}
+	}
 
-	if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
-			   "to remain on channel (%u MHz) for Listen "
-			   "state", freq);
-		wpa_s->pending_listen_freq = 0;
+	if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb,
+			   lwork) < 0) {
+		wpas_p2p_listen_work_free(lwork);
 		return -1;
 	}
-	wpa_s->off_channel_freq = 0;
-	wpa_s->roc_waiting_drv_freq = freq;
 
 	return 0;
 }
@@ -1482,6 +1839,7 @@
 	}
 	wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
 	wpa_drv_probe_req_report(wpa_s, 0);
+	wpas_p2p_listen_work_done(wpa_s);
 }
 
 
@@ -1982,8 +2340,8 @@
 #endif /* CONFIG_WIFI_DISPLAY */
 
 
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
-		     u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+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;
@@ -2100,8 +2458,8 @@
 }
 
 
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
-		      const u8 *tlvs, size_t tlvs_len)
+static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+			     const u8 *tlvs, size_t tlvs_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	const u8 *pos = tlvs;
@@ -2168,8 +2526,6 @@
 u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
 			const struct wpabuf *tlvs)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_sd_request(wpa_s, dst, 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);
@@ -2201,8 +2557,6 @@
 static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
 				   const struct wpabuf *tlvs)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return 0;
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return 0;
 	return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
@@ -2280,8 +2634,6 @@
 
 int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 	return p2p_sd_cancel_request(wpa_s->global->p2p,
@@ -2293,11 +2645,6 @@
 			  const u8 *dst, u8 dialog_token,
 			  const struct wpabuf *resp_tlvs)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
-					resp_tlvs);
-		return;
-	}
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 	p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
@@ -2307,10 +2654,6 @@
 
 void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		wpa_drv_p2p_service_update(wpa_s);
-		return;
-	}
 	if (wpa_s->global->p2p)
 		p2p_sd_service_update(wpa_s->global->p2p);
 }
@@ -2435,11 +2778,11 @@
 }
 
 
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
-			const u8 *dev_addr, const u8 *pri_dev_type,
-			const char *dev_name, u16 supp_config_methods,
-			u8 dev_capab, u8 group_capab, const u8 *group_id,
-			size_t group_id_len)
+static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+			       const u8 *dev_addr, const u8 *pri_dev_type,
+			       const char *dev_name, u16 supp_config_methods,
+			       u8 dev_capab, u8 group_capab, const u8 *group_id,
+			       size_t group_id_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -2492,7 +2835,7 @@
 }
 
 
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	unsigned int generated_pin = 0;
@@ -2504,7 +2847,7 @@
 		wpa_s->pending_pd_before_join = 0;
 		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
 			   "join-existing-group operation");
-		wpas_p2p_join_start(wpa_s);
+		wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 		return;
 	}
 
@@ -2548,7 +2891,7 @@
 		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
 			   "join-existing-group operation (no ACK for PD "
 			   "Req attempts)");
-		wpas_p2p_join_start(wpa_s);
+		wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 		return;
 	}
 
@@ -2574,7 +2917,8 @@
 				  const u8 *go_dev_addr, const u8 *ssid,
 				  size_t ssid_len, int *go, u8 *group_bssid,
 				  int *force_freq, int persistent_group,
-				  const struct p2p_channels *channels)
+				  const struct p2p_channels *channels,
+				  int dev_pw_id)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
@@ -2583,7 +2927,8 @@
 
 	if (!persistent_group) {
 		wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
-			   " to join an active group", MAC2STR(sa));
+			   " to join an active group (SSID: %s)",
+			   MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len));
 		if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
 		    (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
 		     == 0 ||
@@ -2592,6 +2937,21 @@
 				   "authorized invitation");
 			goto accept_inv;
 		}
+
+#ifdef CONFIG_WPS_NFC
+		if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
+		    dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+			wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
+			wpa_s->parent->p2p_wps_method = WPS_NFC;
+			wpa_s->parent->pending_join_wps_method = WPS_NFC;
+			os_memcpy(wpa_s->parent->pending_join_dev_addr,
+				  go_dev_addr, ETH_ALEN);
+			os_memcpy(wpa_s->parent->pending_join_iface_addr,
+				  bssid, ETH_ALEN);
+			goto accept_inv;
+		}
+#endif /* CONFIG_WPS_NFC */
+
 		/*
 		 * Do not accept the invitation automatically; notify user and
 		 * request approval.
@@ -2656,9 +3016,14 @@
 
 	/* Get one of the frequencies currently in use */
 	if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
-		*force_freq = res;
+		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
 		wpas_p2p_set_own_freq_preference(wpa_s, res);
+
+		if (wpa_s->num_multichan_concurrent < 2 ||
+		    wpas_p2p_num_unused_channels(wpa_s) < 1) {
+			wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
+			*force_freq = res;
+		}
 	}
 
 	if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
@@ -2701,16 +3066,18 @@
 
 	if (status == P2P_SC_SUCCESS) {
 		wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
-			   " was accepted; op_freq=%d MHz",
-			   MAC2STR(sa), op_freq);
+			   " was accepted; op_freq=%d MHz, SSID=%s",
+			   MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
 		if (s) {
 			int go = s->mode == WPAS_MODE_P2P_GO;
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, go, go ? op_freq : 0, 0, NULL);
+				wpa_s, s, go, 0, go ? op_freq : 0, 0, 0, NULL,
+				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-				      wpa_s->p2p_wps_method, 0);
+				      wpa_s->p2p_wps_method, 0, op_freq,
+				      ssid, ssid_len);
 		}
 		return;
 	}
@@ -2813,7 +3180,7 @@
 
 static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
 				   const struct p2p_channels *channels,
-				   const u8 *peer)
+				   const u8 *peer, int neg_freq)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid;
@@ -2868,38 +3235,28 @@
 	 * the persistent group so that we will remain on the current channel to
 	 * acknowledge any possible retransmission from the peer.
 	 */
-#ifndef ANDROID_P2P
 	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
 		"starting persistent group");
 	os_sleep(0, 50000);
-#else
-	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 100 ms wait on current channel before "
-		"starting persistent group");
-	os_sleep(0, 100000);
-#endif
 
 	wpas_p2p_group_add_persistent(wpa_s, ssid,
 				      ssid->mode == WPAS_MODE_P2P_GO,
 				      wpa_s->p2p_persistent_go_freq,
-				      wpa_s->p2p_go_ht40, channels);
+				      neg_freq,
+				      wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+				      channels,
+				      ssid->mode == WPAS_MODE_P2P_GO ?
+				      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+				      0);
 }
 
 
 static int wpas_p2p_disallowed_freq(struct wpa_global *global,
 				    unsigned int freq)
 {
-	unsigned int i;
-
-	if (global->p2p_disallow_freq == NULL)
-		return 0;
-
-	for (i = 0; i < global->num_p2p_disallow_freq; i++) {
-		if (freq >= global->p2p_disallow_freq[i].min &&
-		    freq <= global->p2p_disallow_freq[i].max)
-			return 1;
-	}
-
-	return 0;
+	if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq))
+		return 1;
+	return freq_range_list_includes(&global->p2p_disallow_freq, freq);
 }
 
 
@@ -2911,10 +3268,13 @@
 
 
 static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
-				     struct p2p_channels *chan)
+				     struct p2p_channels *chan,
+				     struct p2p_channels *cli_chan)
 {
 	int i, cla = 0;
 
+	os_memset(cli_chan, 0, sizeof(*cli_chan));
+
 	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
 		   "band");
 
@@ -2982,6 +3342,10 @@
 }
 
 
+enum chan_allowed {
+	NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+};
+
 static int has_channel(struct wpa_global *global,
 		       struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
@@ -2991,21 +3355,25 @@
 	freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
 		chan * 5;
 	if (wpas_p2p_disallowed_freq(global, freq))
-		return 0;
+		return NOT_ALLOWED;
 
 	for (i = 0; i < mode->num_channels; i++) {
 		if (mode->channels[i].chan == chan) {
 			if (flags)
 				*flags = mode->channels[i].flag;
-			return !(mode->channels[i].flag &
-				 (HOSTAPD_CHAN_DISABLED |
-				  HOSTAPD_CHAN_PASSIVE_SCAN |
-				  HOSTAPD_CHAN_NO_IBSS |
-				  HOSTAPD_CHAN_RADAR));
+			if (mode->channels[i].flag &
+			    (HOSTAPD_CHAN_DISABLED |
+			     HOSTAPD_CHAN_RADAR))
+				return NOT_ALLOWED;
+			if (mode->channels[i].flag &
+			    (HOSTAPD_CHAN_PASSIVE_SCAN |
+			     HOSTAPD_CHAN_NO_IBSS))
+				return PASSIVE_ONLY;
+			return ALLOWED;
 		}
 	}
 
-	return 0;
+	return NOT_ALLOWED;
 }
 
 
@@ -3015,7 +3383,7 @@
 	u8 min_chan;
 	u8 max_chan;
 	u8 inc;
-	enum { BW20, BW40PLUS, BW40MINUS } bw;
+	enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
 };
 
 static struct p2p_oper_class_map op_class[] = {
@@ -3030,73 +3398,171 @@
 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+
+	/*
+	 * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
+	 * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
+	 * 80 MHz, but currently use the following definition for simplicity
+	 * (these center frequencies are not actual channels, which makes
+	 * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
+	 * removing invalid channels.
+	 */
+	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
 	{ -1, 0, 0, 0, 0, BW20 }
 };
 
 
-static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
-				   struct hostapd_hw_modes *mode,
-				   u8 channel, u8 bw)
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+				     struct hostapd_hw_modes *mode,
+				     u8 channel)
 {
-	int flag;
+	u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+	unsigned int i;
 
-	if (!has_channel(wpa_s->global, mode, channel, &flag))
-		return -1;
-	if (bw == BW40MINUS &&
-	    (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-	     !has_channel(wpa_s->global, mode, channel - 4, NULL)))
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
 		return 0;
-	if (bw == BW40PLUS &&
-	    (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-	     !has_channel(wpa_s->global, mode, channel + 4, NULL)))
-		return 0;
-	return 1;
+
+	for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+		/*
+		 * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+		 * so the center channel is 6 channels away from the start/end.
+		 */
+		if (channel >= center_channels[i] - 6 &&
+		    channel <= center_channels[i] + 6)
+			return center_channels[i];
+
+	return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
+					       struct hostapd_hw_modes *mode,
+					       u8 channel, u8 bw)
+{
+	u8 center_chan;
+	int i, flags;
+	enum chan_allowed res, ret = ALLOWED;
+
+	center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+	if (!center_chan)
+		return NOT_ALLOWED;
+	if (center_chan >= 58 && center_chan <= 138)
+		return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+	/* check all the channels are available */
+	for (i = 0; i < 4; i++) {
+		int adj_chan = center_chan - 6 + i * 4;
+
+		res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+		if (res == NOT_ALLOWED)
+			return NOT_ALLOWED;
+		if (res == PASSIVE_ONLY)
+			ret = PASSIVE_ONLY;
+
+		if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+			return NOT_ALLOWED;
+		if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+			return NOT_ALLOWED;
+		if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+			return NOT_ALLOWED;
+		if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+			return NOT_ALLOWED;
+	}
+
+	return ret;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+						 struct hostapd_hw_modes *mode,
+						 u8 channel, u8 bw)
+{
+	int flag = 0;
+	enum chan_allowed res, res2;
+
+	res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+	if (bw == BW40MINUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+			return NOT_ALLOWED;
+		res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+	} else if (bw == BW40PLUS) {
+		if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+			return NOT_ALLOWED;
+		res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+	} else if (bw == BW80) {
+		res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+	}
+
+	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+		return NOT_ALLOWED;
+	if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
+		return PASSIVE_ONLY;
+	return res;
 }
 
 
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
-				   struct p2p_channels *chan)
+				   struct p2p_channels *chan,
+				   struct p2p_channels *cli_chan)
 {
 	struct hostapd_hw_modes *mode;
-	int cla, op;
+	int cla, op, cli_cla;
 
 	if (wpa_s->hw.modes == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
 			   "of all supported channels; assume dualband "
 			   "support");
-		return wpas_p2p_default_channels(wpa_s, chan);
+		return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
 	}
 
-	cla = 0;
+	cla = cli_cla = 0;
 
 	for (op = 0; op_class[op].op_class; op++) {
 		struct p2p_oper_class_map *o = &op_class[op];
 		u8 ch;
-		struct p2p_reg_class *reg = NULL;
+		struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
 
 		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
 		if (mode == NULL)
 			continue;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-			if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
-				continue;
-			if (reg == NULL) {
-				wpa_printf(MSG_DEBUG, "P2P: Add operating "
-					   "class %u", o->op_class);
-				reg = &chan->reg_class[cla];
-				cla++;
-				reg->reg_class = o->op_class;
+			enum chan_allowed res;
+			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+			if (res == ALLOWED) {
+				if (reg == NULL) {
+					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+						   o->op_class);
+					reg = &chan->reg_class[cla];
+					cla++;
+					reg->reg_class = o->op_class;
+				}
+				reg->channel[reg->channels] = ch;
+				reg->channels++;
+			} else if (res == PASSIVE_ONLY &&
+				   wpa_s->conf->p2p_add_cli_chan) {
+				if (cli_reg == NULL) {
+					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+						   o->op_class);
+					cli_reg = &cli_chan->reg_class[cli_cla];
+					cli_cla++;
+					cli_reg->reg_class = o->op_class;
+				}
+				cli_reg->channel[cli_reg->channels] = ch;
+				cli_reg->channels++;
 			}
-			reg->channel[reg->channels] = ch;
-			reg->channels++;
 		}
 		if (reg) {
 			wpa_hexdump(MSG_DEBUG, "P2P: Channels",
 				    reg->channel, reg->channels);
 		}
+		if (cli_reg) {
+			wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+				    cli_reg->channel, cli_reg->channels);
+		}
 	}
 
 	chan->reg_classes = cla;
+	cli_chan->reg_classes = cli_cla;
 
 	return 0;
 }
@@ -3105,7 +3571,8 @@
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel)
 {
-	int op, ret;
+	int op;
+	enum chan_allowed ret;
 
 	for (op = 0; op_class[op].op_class; op++) {
 		struct p2p_oper_class_map *o = &op_class[op];
@@ -3116,18 +3583,24 @@
 			    o->bw == BW20 || ch != channel)
 				continue;
 			ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
-			if (ret < 0)
-				continue;
-			else if (ret > 0)
+			if (ret == ALLOWED)
 				return (o->bw == BW40MINUS) ? -1 : 1;
-			else
-				return 0;
 		}
 	}
 	return 0;
 }
 
 
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+			      struct hostapd_hw_modes *mode, u8 channel)
+{
+	if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+		return 0;
+
+	return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
 			size_t buf_len)
 {
@@ -3165,6 +3638,21 @@
 }
 
 
+static int wpas_is_concurrent_session_active(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_supplicant *ifs;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s)
+			continue;
+		if (ifs->wpa_state > WPA_ASSOCIATED)
+			return 1;
+	}
+	return 0;
+}
+
+
 static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -3211,6 +3699,28 @@
 }
 
 
+static void wpas_presence_resp(void *ctx, const u8 *src, u8 status,
+			       const u8 *noa, size_t noa_len)
+{
+	struct wpa_supplicant *wpa_s, *intf = ctx;
+	char hex[100];
+
+	for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (wpa_s->waiting_presence_resp)
+			break;
+	}
+	if (!wpa_s) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response");
+		return;
+	}
+	wpa_s->waiting_presence_resp = 0;
+
+	wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len);
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR
+		" status=%u noa=%s", MAC2STR(src), status, hex);
+}
+
+
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -3232,25 +3742,6 @@
 	if (global->p2p)
 		return 0;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		struct p2p_params params;
-
-		wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
-		os_memset(&params, 0, sizeof(params));
-		params.dev_name = wpa_s->conf->device_name;
-		os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
-			  WPS_DEV_TYPE_LEN);
-		params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
-		os_memcpy(params.sec_dev_type,
-			  wpa_s->conf->sec_device_type,
-			  params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
-
-		if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
-			return -1;
-
-		return 0;
-	}
-
 	os_memset(&p2p, 0, sizeof(p2p));
 	p2p.cb_ctx = wpa_s;
 	p2p.debug_print = wpas_p2p_debug_print;
@@ -3275,6 +3766,8 @@
 	p2p.invitation_result = wpas_invitation_result;
 	p2p.get_noa = wpas_get_noa;
 	p2p.go_connected = wpas_go_connected;
+	p2p.presence_resp = wpas_presence_resp;
+	p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
 
 	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
 	os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -3335,7 +3828,7 @@
 	} else
 		os_memcpy(p2p.country, "XX\x04", 3);
 
-	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
 			   "channel list");
 		return -1;
@@ -3378,6 +3871,8 @@
 			global->p2p, wpa_s->conf->wps_vendor_ext[i]);
 	}
 
+	p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
 	return 0;
 }
 
@@ -3402,15 +3897,23 @@
 
 	os_free(wpa_s->go_params);
 	wpa_s->go_params = NULL;
-#ifdef ANDROID_P2P
-	eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
-#endif
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 	wpa_s->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 	wpas_p2p_remove_pending_group_interface(wpa_s);
+	eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+	wpas_p2p_listen_work_done(wpa_s);
+	if (wpa_s->p2p_send_action_work) {
+		os_free(wpa_s->p2p_send_action_work->ctx);
+		radio_work_done(wpa_s->p2p_send_action_work);
+		wpa_s->p2p_send_action_work = NULL;
+	}
+	eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+
+	wpabuf_free(wpa_s->p2p_oob_dev_pw);
+	wpa_s->p2p_oob_dev_pw = NULL;
 
 	/* TODO: remove group interface from the driver if this wpa_s instance
 	 * is on top of a P2P group interface */
@@ -3495,12 +3998,6 @@
 	if (persistent_group && wpa_s->conf->persistent_reconnect)
 		persistent_group = 2;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
-					   go_intent, own_interface_addr,
-					   force_freq, persistent_group);
-	}
-
 	/*
 	 * Increase GO config timeout if HT40 is used since it takes some time
 	 * to scan channels for coex purposes before the BSS can be started.
@@ -3512,7 +4009,9 @@
 			   go_intent, own_interface_addr, force_freq,
 			   persistent_group, ssid ? ssid->ssid : NULL,
 			   ssid ? ssid->ssid_len : 0,
-			   wpa_s->p2p_pd_before_go_neg, pref_freq);
+			   wpa_s->p2p_pd_before_go_neg, pref_freq,
+			   wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+			   0);
 }
 
 
@@ -3526,13 +4025,12 @@
 	if (persistent_group && wpa_s->conf->persistent_reconnect)
 		persistent_group = 2;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return -1;
-
 	return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
 			     go_intent, own_interface_addr, force_freq,
 			     persistent_group, ssid ? ssid->ssid : NULL,
-			     ssid ? ssid->ssid_len : 0, pref_freq);
+			     ssid ? ssid->ssid_len : 0, pref_freq,
+			     wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+			     0);
 }
 
 
@@ -3612,7 +4110,8 @@
 		return 0;
 	}
 
-	updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+	updated = os_reltime_before(&wpa_s->p2p_auto_started,
+				    &bss->last_update);
 	wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
 		   "%ld.%06ld (%supdated in last scan)",
 		   bss->last_update.sec, bss->last_update.usec,
@@ -3625,7 +4124,7 @@
 static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 				   struct wpa_scan_results *scan_res)
 {
-	struct wpa_bss *bss;
+	struct wpa_bss *bss = NULL;
 	int freq;
 	u8 iface_addr[ETH_ALEN];
 
@@ -3657,7 +4156,7 @@
 					   MAC2STR(wpa_s->
 						   pending_join_dev_addr),
 					   freq);
-				wpas_p2p_join_scan_req(wpa_s, freq);
+				wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0);
 				return;
 			}
 		}
@@ -3695,7 +4194,8 @@
 					 wpa_s->p2p_connect_freq,
 					 wpa_s->p2p_persistent_id,
 					 wpa_s->p2p_pd_before_go_neg,
-					 wpa_s->p2p_go_ht40);
+					 wpa_s->p2p_go_ht40,
+					 wpa_s->p2p_go_vht);
 			return;
 		}
 
@@ -3729,11 +4229,27 @@
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
 			   "from P2P peer table: %d MHz", freq);
 	}
-	bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
+	if (wpa_s->p2p_join_ssid_len) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+			   MACSTR " and SSID %s",
+			   MAC2STR(wpa_s->pending_join_iface_addr),
+			   wpa_ssid_txt(wpa_s->p2p_join_ssid,
+					wpa_s->p2p_join_ssid_len));
+		bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+				  wpa_s->p2p_join_ssid,
+				  wpa_s->p2p_join_ssid_len);
+	}
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+			   MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
+		bss = wpa_bss_get_bssid_latest(wpa_s,
+					       wpa_s->pending_join_iface_addr);
+	}
 	if (bss) {
 		freq = bss->freq;
 		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
-			   "from BSS table: %d MHz", freq);
+			   "from BSS table: %d MHz (SSID %s)", freq,
+			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	}
 	if (freq > 0) {
 		u16 method;
@@ -3801,34 +4317,33 @@
 
 start:
 	/* Start join operation immediately */
-	wpas_p2p_join_start(wpa_s);
+	wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 }
 
 
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+				   const u8 *ssid, size_t ssid_len)
 {
 	int ret;
 	struct wpa_driver_scan_params params;
 	struct wpabuf *wps_ie, *ies;
 	size_t ielen;
 	int freqs[2] = { 0, 0 };
-#ifdef ANDROID_P2P
-	int oper_freq;
 
-	/* If freq is not provided, check the operating freq of the GO and do a
-	 * a directed scan to save time
-	 */
-	if(!freq) {
-		freq = (oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
-			 wpa_s->pending_join_iface_addr) == -1) ? 0 : oper_freq; 
-	}
-#endif
 	os_memset(&params, 0, sizeof(params));
 
 	/* P2P Wildcard SSID */
 	params.num_ssids = 1;
-	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
-	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+	if (ssid && ssid_len) {
+		params.ssids[0].ssid = ssid;
+		params.ssids[0].ssid_len = ssid_len;
+		os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len);
+		wpa_s->p2p_join_ssid_len = ssid_len;
+	} else {
+		params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+		params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+		wpa_s->p2p_join_ssid_len = 0;
+	}
 
 	wpa_s->wps->dev.p2p = 1;
 	wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
@@ -3854,6 +4369,18 @@
 	params.p2p_probe = 1;
 	params.extra_ies = wpabuf_head(ies);
 	params.extra_ies_len = wpabuf_len(ies);
+
+	if (!freq) {
+		int oper_freq;
+		/*
+		 * If freq is not provided, check the operating freq of the GO
+		 * and use a single channel scan on if possible.
+		 */
+		oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
+					      wpa_s->pending_join_iface_addr);
+		if (oper_freq > 0)
+			freq = oper_freq;
+	}
 	if (freq > 0) {
 		freqs[0] = freq;
 		params.freqs = freqs;
@@ -3865,8 +4392,9 @@
 	 */
 	ret = wpa_drv_scan(wpa_s, &params);
 	if (!ret) {
-		os_get_time(&wpa_s->scan_trigger_time);
+		os_get_reltime(&wpa_s->scan_trigger_time);
 		wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+		wpa_s->own_scan_requested = 1;
 	}
 
 	wpabuf_free(ies);
@@ -3884,18 +4412,23 @@
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
-	wpas_p2p_join_scan_req(wpa_s, 0);
+	wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0);
 }
 
 
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 			 const u8 *dev_addr, enum p2p_wps_method wps_method,
-			 int auto_join)
+			 int auto_join, int op_freq,
+			 const u8 *ssid, size_t ssid_len)
 {
 	wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
-		   MACSTR " dev " MACSTR ")%s",
-		   MAC2STR(iface_addr), MAC2STR(dev_addr),
+		   MACSTR " dev " MACSTR " op_freq=%d)%s",
+		   MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq,
 		   auto_join ? " (auto_join)" : "");
+	if (ssid && ssid_len) {
+		wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
+			   wpa_ssid_txt(ssid, ssid_len));
+	}
 
 	wpa_s->p2p_auto_pd = 0;
 	wpa_s->p2p_auto_join = !!auto_join;
@@ -3907,12 +4440,13 @@
 	wpas_p2p_stop_find(wpa_s);
 
 	wpa_s->p2p_join_scan_count = 0;
-	wpas_p2p_join_scan(wpa_s, NULL);
+	wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len);
 	return 0;
 }
 
 
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+			       const u8 *ssid, size_t ssid_len)
 {
 	struct wpa_supplicant *group;
 	struct p2p_go_neg_results res;
@@ -3940,14 +4474,25 @@
 	group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
 
 	os_memset(&res, 0, sizeof(res));
+	os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
 	os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
 		  ETH_ALEN);
 	res.wps_method = wpa_s->pending_join_wps_method;
-	bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
-	if (bss) {
-		res.freq = bss->freq;
-		res.ssid_len = bss->ssid_len;
-		os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+	if (freq && ssid && ssid_len) {
+		res.freq = freq;
+		res.ssid_len = ssid_len;
+		os_memcpy(res.ssid, ssid, ssid_len);
+	} else {
+		bss = wpa_bss_get_bssid_latest(wpa_s,
+					       wpa_s->pending_join_iface_addr);
+		if (bss) {
+			res.freq = bss->freq;
+			res.ssid_len = bss->ssid_len;
+			os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+			wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
+				   bss->freq,
+				   wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		}
 	}
 
 	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -3973,7 +4518,7 @@
 
 
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
-				int *force_freq, int *pref_freq)
+				int *force_freq, int *pref_freq, int go)
 {
 	int *freqs, res;
 	unsigned int freq_in_use = 0, num, i;
@@ -3989,7 +4534,12 @@
 		   freq, wpa_s->num_multichan_concurrent, num);
 
 	if (freq > 0) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+		int ret;
+		if (go)
+			ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+		else
+			ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
+		if (!ret) {
 			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
 				   "(%u MHz) is not supported for P2P uses",
 				   freq);
@@ -4018,29 +4568,25 @@
 		if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
 			continue;
 
-#ifndef ANDROID_P2P
-		wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
-			   *force_freq);
-		*force_freq = freqs[i];
-#endif
-
 		if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
-			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using");
+			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
+				   freqs[i]);
 			*pref_freq = freqs[i];
-#ifdef ANDROID_P2P
 		} else {
 			wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
-				   *force_freq);
+				   freqs[i]);
 			*force_freq = freqs[i];
-#endif
 		}
 		break;
 	}
 
 	if (i == num) {
-		if (num < wpa_s->num_multichan_concurrent) {
+		if (num < wpa_s->num_multichan_concurrent && num > 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
 			*force_freq = 0;
+		} else if (num < wpa_s->num_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new channel");
+			*force_freq = 0;
 		} else {
 			wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
 			res = -2;
@@ -4074,6 +4620,7 @@
  * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
  *	interoperability workaround when initiating group formation
  * @ht40: Start GO with 40 MHz channel width
+ * @vht:  Start GO with VHT support
  * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
  *	failure, -2 on failure due to channel not currently available,
  *	-3 if forced channel is not supported
@@ -4082,7 +4629,7 @@
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join, int auth,
 		     int go_intent, int freq, int persistent_id, int pd,
-		     int ht40)
+		     int ht40, int vht)
 {
 	int force_freq = 0, pref_freq = 0;
 	int ret = 0, res;
@@ -4103,6 +4650,8 @@
 	os_free(wpa_s->global->add_psk);
 	wpa_s->global->add_psk = NULL;
 
+	wpa_s->global->p2p_fail_on_wps_complete = 0;
+
 	if (go_intent < 0)
 		go_intent = wpa_s->conf->p2p_go_intent;
 
@@ -4117,6 +4666,7 @@
 	wpa_s->p2p_fallback_to_go_neg = 0;
 	wpa_s->p2p_pd_before_go_neg = !!pd;
 	wpa_s->p2p_go_ht40 = !!ht40;
+	wpa_s->p2p_go_vht = !!vht;
 
 	if (pin)
 		os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -4146,7 +4696,7 @@
 					 dev_addr);
 		}
 		if (auto_join) {
-			os_get_time(&wpa_s->p2p_auto_started);
+			os_get_reltime(&wpa_s->p2p_auto_started);
 			wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
 				   "%ld.%06ld",
 				   wpa_s->p2p_auto_started.sec,
@@ -4154,15 +4704,17 @@
 		}
 		wpa_s->user_initiated_pd = 1;
 		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
-				  auto_join) < 0)
+				  auto_join, freq, NULL, 0) < 0)
 			return -1;
 		return ret;
 	}
 
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   go_intent == 15);
 	if (res)
 		return res;
-	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
+	wpas_p2p_set_own_freq_preference(wpa_s,
+					 force_freq ? force_freq : pref_freq);
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -4219,6 +4771,10 @@
 		p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
 			      wpa_s->pending_listen_duration);
 		wpa_s->pending_listen_freq = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d freq=%u duration=%u)",
+			   wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+			   freq, duration);
 	}
 }
 
@@ -4230,9 +4786,6 @@
 	if (timeout > wpa_s->max_remain_on_chan)
 		timeout = wpa_s->max_remain_on_chan;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_listen(wpa_s, timeout);
-
 	return p2p_listen(wpa_s->global->p2p, timeout);
 }
 
@@ -4252,6 +4805,7 @@
 	wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
 		   "(p2p_long_listen=%d ms pending_action_tx=%p)",
 		   wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+	wpas_p2p_listen_work_done(wpa_s);
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 	if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
@@ -4322,8 +4876,8 @@
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
 			   "band");
 		if (wpa_s->best_24_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
-				       wpa_s->best_24_freq)) {
+		    p2p_supported_freq_go(wpa_s->global->p2p,
+					  wpa_s->best_24_freq)) {
 			freq = wpa_s->best_24_freq;
 			wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
 				   "channel: %d MHz", freq);
@@ -4339,7 +4893,7 @@
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
 			   "band");
 		if (wpa_s->best_5_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
+		    p2p_supported_freq_go(wpa_s->global->p2p,
 				       wpa_s->best_5_freq)) {
 			freq = wpa_s->best_5_freq;
 			wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
@@ -4347,7 +4901,7 @@
 		} else {
 			os_get_random((u8 *) &r, sizeof(r));
 			freq = 5180 + (r % 4) * 20;
-			if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+			if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 				wpa_printf(MSG_DEBUG, "P2P: Could not select "
 					   "5 GHz channel for P2P group");
 				return -1;
@@ -4357,7 +4911,7 @@
 		}
 	}
 
-	if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+	if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
 			   "(%u MHz) is not supported for P2P uses",
 			   freq);
@@ -4370,7 +4924,7 @@
 
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
-				   int freq, int ht40,
+				   int freq, int ht40, int vht,
 				   const struct p2p_channels *channels)
 {
 	int res, *freqs;
@@ -4380,6 +4934,7 @@
 	os_memset(params, 0, sizeof(*params));
 	params->role_go = 1;
 	params->ht40 = ht40;
+	params->vht = vht;
 	if (freq) {
 		if (!freq_included(channels, freq)) {
 			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
@@ -4410,24 +4965,24 @@
 			   "frequency %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_overall_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_overall_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_overall_freq) &&
 		   freq_included(channels, wpa_s->best_overall_freq)) {
 		params->freq = wpa_s->best_overall_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_24_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_24_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_24_freq) &&
 		   freq_included(channels, wpa_s->best_24_freq)) {
 		params->freq = wpa_s->best_24_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
 			   "channel %d MHz", params->freq);
 	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
 		   wpa_s->best_5_freq > 0 &&
-		   p2p_supported_freq(wpa_s->global->p2p,
-				      wpa_s->best_5_freq) &&
+		   p2p_supported_freq_go(wpa_s->global->p2p,
+					 wpa_s->best_5_freq) &&
 		   freq_included(channels, wpa_s->best_5_freq)) {
 		params->freq = wpa_s->best_5_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
@@ -4467,41 +5022,32 @@
 	}
 	num = res;
 
-	if (!freq) {
-		for (i = 0; i < num; i++) {
-			if (freq_included(channels, freqs[i])) {
-				wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
-					   freqs[i]);
-				params->freq = freqs[i];
-				break;
-			}
-		}
-
-		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
-				os_free(freqs);
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
-			}
-		}
-	} else {
-		for (i = 0; i < num; i++) {
-			if (freqs[i] == freq)
-				break;
-		}
-
-		if (i == num) {
-			if (num == wpa_s->num_multichan_concurrent) {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
-				os_free(freqs);
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
-			}
+	for (i = 0; i < num; i++) {
+		if (freq && freqs[i] == freq)
+			break;
+		if (!freq && freq_included(channels, freqs[i])) {
+			wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+				   freqs[i]);
+			params->freq = freqs[i];
+			break;
 		}
 	}
+
+	if (i == num) {
+		if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+			if (freq)
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+			else
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+			os_free(freqs);
+			return -1;
+		} else if (num == 0) {
+			wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
+		} else {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+		}
+	}
+
 	os_free(freqs);
 	return 0;
 }
@@ -4516,6 +5062,7 @@
 	if (!wpas_p2p_create_iface(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
 			"operations");
+		wpa_s->p2p_first_connection_timeout = 0;
 		return wpa_s;
 	}
 
@@ -4535,6 +5082,7 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
 		group_wpa_s->ifname);
+	group_wpa_s->p2p_first_connection_timeout = 0;
 	return group_wpa_s;
 }
 
@@ -4544,13 +5092,15 @@
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
  * @persistent_group: Whether to create a persistent group
  * @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @ht40: Start GO with 40 MHz channel width
+ * @vht:  Start GO with VHT support
  * Returns: 0 on success, -1 on failure
  *
  * This function creates a new P2P group with the local end as the Group Owner,
  * i.e., without using Group Owner Negotiation.
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq, int ht40)
+		       int freq, int ht40, int vht)
 {
 	struct p2p_go_neg_results params;
 
@@ -4568,10 +5118,10 @@
 	if (freq < 0)
 		return -1;
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
 		return -1;
 	if (params.freq &&
-	    !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+	    !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
 		wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
 			   "(%u MHz) is not supported for P2P uses",
 			   params.freq);
@@ -4626,21 +5176,22 @@
 	if (params->passphrase)
 		ssid->passphrase = os_strdup(params->passphrase);
 
-	wpa_supplicant_select_network(wpa_s, ssid);
-
 	wpa_s->show_group_started = 1;
 
+	wpa_supplicant_select_network(wpa_s, ssid);
+
 	return 0;
 }
 
 
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40,
-				  const struct p2p_channels *channels)
+				  int force_freq, int neg_freq, int ht40,
+				  int vht, const struct p2p_channels *channels,
+				  int connection_timeout)
 {
 	struct p2p_go_neg_results params;
-	int go = 0;
+	int go = 0, freq;
 
 	if (ssid->disabled != 2 || ssid->ssid == NULL)
 		return -1;
@@ -4666,11 +5217,17 @@
 	if (ssid->mode != WPAS_MODE_P2P_GO)
 		return -1;
 
-	freq = wpas_p2p_select_go_freq(wpa_s, freq);
-	if (freq < 0)
-		return -1;
+	if (force_freq > 0) {
+		freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+		if (freq < 0)
+			return -1;
+	} else {
+		freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+		if (freq < 0 || (freq > 0 && !freq_included(channels, freq)))
+			freq = 0;
+	}
 
-	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
 		return -1;
 
 	params.role_go = 1;
@@ -4694,6 +5251,7 @@
 	if (wpa_s == NULL)
 		return -1;
 
+	wpa_s->p2p_first_connection_timeout = connection_timeout;
 	wpas_start_wps_go(wpa_s, &params, 0);
 
 	return 0;
@@ -4731,9 +5289,14 @@
 	if (!wpa_s->ap_iface)
 		return;
 	wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
-	if (idle)
+	if (idle) {
+		if (wpa_s->global->p2p_fail_on_wps_complete &&
+		    wpa_s->p2p_in_provisioning) {
+			wpas_p2p_grpform_fail_after_wps(wpa_s);
+			return;
+		}
 		wpas_p2p_set_group_idle_timeout(wpa_s);
-	else
+	} else
 		eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 }
 
@@ -4744,8 +5307,6 @@
 	struct p2p_group *group;
 	struct p2p_group_config *cfg;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return NULL;
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return NULL;
 
@@ -4765,6 +5326,7 @@
 		cfg->max_clients = wpa_s->conf->max_num_sta;
 	os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
 	cfg->ssid_len = ssid->ssid_len;
+	cfg->freq = ssid->frequency;
 	cfg->cb_ctx = wpa_s;
 	cfg->ie_update = wpas_p2p_ie_update;
 	cfg->idle_update = wpas_p2p_idle_update;
@@ -4801,6 +5363,7 @@
 
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
 			     NULL);
+	wpa_s->p2p_go_group_formation_completed = 1;
 	if (ssid && ssid->mode == WPAS_MODE_INFRA) {
 		/*
 		 * Use a separate timeout for initial data connection to
@@ -4808,14 +5371,31 @@
 		 * something goes wrong in this step before the P2P group idle
 		 * timeout mechanism is taken into use.
 		 */
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P: Re-start group formation timeout (%d seconds) as client for initial connection",
+			P2P_MAX_INITIAL_CONN_WAIT);
 		eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
 				       wpas_p2p_group_formation_timeout,
 				       wpa_s->parent, NULL);
+	} else if (ssid) {
+		/*
+		 * Use a separate timeout for initial data connection to
+		 * complete to allow the group to be removed automatically if
+		 * the client does not complete data connection successfully.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P: Re-start group formation timeout (%d seconds) as GO for initial connection",
+			P2P_MAX_INITIAL_CONN_WAIT_GO);
+		eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
+				       wpas_p2p_group_formation_timeout,
+				       wpa_s->parent, NULL);
+		/*
+		 * Complete group formation on first successful data connection
+		 */
+		wpa_s->p2p_go_group_formation_completed = 0;
 	}
 	if (wpa_s->global->p2p)
 		p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
-	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		wpa_drv_wps_success_cb(wpa_s, peer_addr);
 	wpas_group_formation_completed(wpa_s, 1);
 }
 
@@ -4836,6 +5416,31 @@
 	}
 
 	wpas_notify_p2p_wps_failed(wpa_s, fail);
+
+	if (wpa_s == wpa_s->global->p2p_group_formation) {
+		/*
+		 * Allow some time for the failed WPS negotiation exchange to
+		 * complete, but remove the group since group formation cannot
+		 * succeed after provisioning failure.
+		 */
+		wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout");
+		wpa_s->global->p2p_fail_on_wps_complete = 1;
+		eloop_deplete_timeout(0, 50000,
+				      wpas_p2p_group_formation_timeout,
+				      wpa_s->parent, NULL);
+	}
+}
+
+
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->global->p2p_fail_on_wps_complete ||
+	    !wpa_s->p2p_in_provisioning)
+		return 0;
+
+	wpas_p2p_grpform_fail_after_wps(wpa_s);
+
+	return 1;
 }
 
 
@@ -4868,7 +5473,7 @@
 		wpa_s->auto_pd_scan_retry = 0;
 		wpas_p2p_stop_find(wpa_s);
 		wpa_s->p2p_join_scan_count = 0;
-		os_get_time(&wpa_s->p2p_auto_started);
+		os_get_reltime(&wpa_s->p2p_auto_started);
 		wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
 			   wpa_s->p2p_auto_started.sec,
 			   wpa_s->p2p_auto_started.usec);
@@ -4876,12 +5481,6 @@
 		return 0;
 	}
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
-						 config_methods,
-						 use == WPAS_P2P_PD_FOR_JOIN);
-	}
-
 	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
 		return -1;
 
@@ -4917,9 +5516,6 @@
 	wpas_p2p_clear_pending_action_tx(wpa_s);
 	wpa_s->p2p_long_listen = 0;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_find(wpa_s, timeout, type);
-
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
 	    wpa_s->p2p_in_provisioning)
 		return -1;
@@ -4938,12 +5534,6 @@
 	wpa_s->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-	wpa_s->global->p2p_cb_on_scan_complete = 0;
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
-		wpa_drv_p2p_stop_find(wpa_s);
-		return 1;
-	}
 
 	if (wpa_s->global->p2p)
 		p2p_stop_find(wpa_s->global->p2p);
@@ -5097,9 +5687,6 @@
 {
 	wpa_s->p2p_long_listen = 0;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_reject(wpa_s, addr);
-
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
@@ -5110,12 +5697,13 @@
 /* Invite to reinvoke a persistent group */
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40, int pref_freq)
+		    int ht40, int vht, int pref_freq)
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
 	int force_freq = 0;
 	int res;
+	int no_pref_freq_given = pref_freq == 0;
 
 	wpa_s->global->p2p_invite_group = NULL;
 	if (peer_addr)
@@ -5149,21 +5737,26 @@
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   role == P2P_INVITE_ROLE_GO);
 	if (res)
 		return res;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
-					  ssid->ssid, ssid->ssid_len,
-					  go_dev_addr, 1);
-
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
+	if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+	    no_pref_freq_given && pref_freq > 0 &&
+	    wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration",
+			   pref_freq);
+		pref_freq = 0;
+	}
+
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
-			  1, pref_freq);
+			  1, pref_freq, -1);
 }
 
 
@@ -5176,11 +5769,12 @@
 	u8 *bssid = NULL;
 	struct wpa_ssid *ssid;
 	int persistent;
-	int force_freq = 0, pref_freq = 0;
+	int freq = 0, force_freq = 0, pref_freq = 0;
 	int res;
 
 	wpa_s->p2p_persistent_go_freq = 0;
 	wpa_s->p2p_go_ht40 = 0;
+	wpa_s->p2p_go_vht = 0;
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 		if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -5208,6 +5802,7 @@
 		bssid = wpa_s->own_addr;
 		if (go_dev_addr == NULL)
 			go_dev_addr = wpa_s->global->p2p_dev_addr;
+		freq = ssid->frequency;
 	} else {
 		role = P2P_INVITE_ROLE_CLIENT;
 		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -5219,25 +5814,23 @@
 		if (go_dev_addr == NULL &&
 		    !is_zero_ether_addr(wpa_s->go_dev_addr))
 			go_dev_addr = wpa_s->go_dev_addr;
+		freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+			(int) wpa_s->assoc_freq;
 	}
 	wpa_s->parent->pending_invite_ssid_id = -1;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
-					  ssid->ssid, ssid->ssid_len,
-					  go_dev_addr, persistent);
-
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+				   role == P2P_INVITE_ROLE_ACTIVE_GO);
 	if (res)
 		return res;
 	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
 
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq,
-			  go_dev_addr, persistent, pref_freq);
+			  go_dev_addr, persistent, pref_freq, -1);
 }
 
 
@@ -5249,6 +5842,8 @@
 	int network_id = -1;
 	int persistent;
 	int freq;
+	u8 ip[3 * 4];
+	char ip_addr[100];
 
 	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
 		eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
@@ -5256,7 +5851,7 @@
 	}
 
 	if (!wpa_s->show_group_started || !ssid)
-		goto done;
+		return;
 
 	wpa_s->show_group_started = 0;
 
@@ -5273,23 +5868,33 @@
 
 	freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
 		(int) wpa_s->assoc_freq;
+
+	ip_addr[0] = '\0';
+	if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
+		os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u "
+			    "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+			    ip[0], ip[1], ip[2], ip[3],
+			    ip[4], ip[5], ip[6], ip[7],
+			    ip[8], ip[9], ip[10], ip[11]);
+	}
+
 	if (ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
 		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
 			       "%s client ssid=\"%s\" freq=%d psk=%s "
-			       "go_dev_addr=" MACSTR "%s",
+			       "go_dev_addr=" MACSTR "%s%s",
 			       wpa_s->ifname, ssid_txt, freq, psk,
 			       MAC2STR(go_dev_addr),
-			       persistent ? " [PERSISTENT]" : "");
+			       persistent ? " [PERSISTENT]" : "", ip_addr);
 	} else {
 		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
 			       "%s client ssid=\"%s\" freq=%d "
-			       "passphrase=\"%s\" go_dev_addr=" MACSTR "%s",
+			       "passphrase=\"%s\" go_dev_addr=" MACSTR "%s%s",
 			       wpa_s->ifname, ssid_txt, freq,
 			       ssid->passphrase ? ssid->passphrase : "",
 			       MAC2STR(go_dev_addr),
-			       persistent ? " [PERSISTENT]" : "");
+			       persistent ? " [PERSISTENT]" : "", ip_addr);
 	}
 
 	if (persistent)
@@ -5298,17 +5903,14 @@
 	if (network_id < 0)
 		network_id = ssid->id;
 	wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
-
-done:
-	wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
 int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
 			  u32 interval1, u32 duration2, u32 interval2)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return -1;
+	int ret;
+
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
@@ -5317,18 +5919,19 @@
 	    wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
 		return -1;
 
-	return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
-				wpa_s->own_addr, wpa_s->assoc_freq,
-				duration1, interval1, duration2, interval2);
+	ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+			       wpa_s->own_addr, wpa_s->assoc_freq,
+			       duration1, interval1, duration2, interval2);
+	if (ret == 0)
+		wpa_s->waiting_presence_resp = 1;
+
+	return ret;
 }
 
 
 int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
 			unsigned int interval)
 {
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return -1;
-
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
@@ -5430,8 +6033,6 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return 0;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return 0;
 
 	if (!locally_generated)
 		p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
@@ -5459,8 +6060,6 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return;
 
 	if (!locally_generated)
 		p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
@@ -5587,6 +6186,11 @@
 			wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
 				   "update failed");
 		}
+
+		if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+				   "update failed");
+		}
 	}
 }
 
@@ -5605,8 +6209,6 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return -1;
 
 	wpa_s->global->cross_connection = enabled;
 	p2p_set_cross_connect(wpa_s->global->p2p, enabled);
@@ -5758,19 +6360,20 @@
 
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 {
-	struct p2p_channels chan;
+	struct p2p_channels chan, cli_chan;
 
 	if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
 		return;
 
 	os_memset(&chan, 0, sizeof(chan));
-	if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+	os_memset(&cli_chan, 0, sizeof(cli_chan));
+	if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
 			   "channel list");
 		return;
 	}
 
-	p2p_update_channel_list(wpa_s->global->p2p, &chan);
+	p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
 }
 
 
@@ -5863,7 +6466,7 @@
 				   int freq_24, int freq_5, int freq_overall)
 {
 	struct p2p_data *p2p = wpa_s->global->p2p;
-	if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+	if (p2p == NULL)
 		return;
 	p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
 }
@@ -5874,7 +6477,7 @@
 	u8 peer[ETH_ALEN];
 	struct p2p_data *p2p = wpa_s->global->p2p;
 
-	if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+	if (p2p == NULL)
 		return -1;
 
 	if (hwaddr_aton(addr, peer))
@@ -5931,10 +6534,10 @@
 	}
 
 	if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
-		struct os_time now;
-		os_get_time(&now);
-		if (now.sec > wpa_s->global->p2p_go_wait_client.sec +
-		    P2P_MAX_INITIAL_CONN_WAIT_GO) {
+		struct os_reltime now;
+		os_get_reltime(&now);
+		if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client,
+				       P2P_MAX_INITIAL_CONN_WAIT_GO)) {
 			/* Wait for the first client has expired */
 			wpa_s->global->p2p_go_wait_client.sec = 0;
 		} else {
@@ -6007,6 +6610,25 @@
 void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 				       const u8 *addr)
 {
+	if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+				 wpa_s->parent, NULL) > 0) {
+		/*
+		 * This can happen if WPS provisioning step is not terminated
+		 * cleanly (e.g., P2P Client does not send WSC_Done). Since the
+		 * peer was able to connect, there is no need to time out group
+		 * formation after this, though. In addition, this is used with
+		 * the initial connection wait on the GO as a separate formation
+		 * timeout and as such, expected to be hit after the initial WPS
+		 * provisioning step.
+		 */
+		wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+	}
+	if (!wpa_s->p2p_go_group_formation_completed) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
+		wpa_s->p2p_go_group_formation_completed = 1;
+		wpa_s->global->p2p_group_formation = NULL;
+		wpa_s->p2p_in_provisioning = 0;
+	}
 	wpa_s->global->p2p_go_wait_client.sec = 0;
 	if (addr == NULL)
 		return;
@@ -6030,7 +6652,8 @@
 			 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
 			 wpa_s->p2p_persistent_id,
 			 wpa_s->p2p_pd_before_go_neg,
-			 wpa_s->p2p_go_ht40);
+			 wpa_s->p2p_go_ht40,
+			 wpa_s->p2p_go_vht);
 }
 
 
@@ -6053,7 +6676,6 @@
 
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
 {
-	const char *rn, *rn2;
 	struct wpa_supplicant *ifs;
 
 	if (wpa_s->wpa_state > WPA_SCANNING) {
@@ -6063,20 +6685,9 @@
 		return P2P_CONCURRENT_SEARCH_DELAY;
 	}
 
-	if (!wpa_s->driver->get_radio_name)
-		return 0;
-	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
-		return 0;
-
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
-			continue;
-
-		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
-		if (!rn2 || os_strcmp(rn, rn2) != 0)
-			continue;
-		if (ifs->wpa_state > WPA_SCANNING) {
+	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+			 radio_list) {
+		if (ifs != wpa_s && ifs->wpa_state > WPA_SCANNING) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
 				"delay due to concurrent operation on "
 				"interface %s",
@@ -6089,30 +6700,6 @@
 }
 
 
-void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
-{
-	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
-		"pending anymore (sta_scan_pending=%d "
-		"p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
-		wpa_s->global->p2p_cb_on_scan_complete);
-	wpa_s->sta_scan_pending = 0;
-
-	if (!wpa_s->global->p2p_cb_on_scan_complete)
-		return;
-	wpa_s->global->p2p_cb_on_scan_complete = 0;
-
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return;
-
-	if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
-			"continued after successful connection");
-		p2p_increase_search_delay(wpa_s->global->p2p,
-					  wpas_p2p_search_delay(wpa_s));
-	}
-}
-
-
 static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s,
 				     struct wpa_ssid *s, const u8 *addr,
 				     int iface_addr)
@@ -6336,6 +6923,63 @@
 }
 
 
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+	wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+					struct wpa_ssid *ssid)
+{
+	struct wpa_supplicant *iface;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		if (!iface->current_ssid ||
+		    iface->current_ssid->frequency == freq ||
+		    (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+		     !iface->current_ssid->p2p_group))
+			continue;
+
+		/* Remove the connection with least priority */
+		if (!wpas_is_p2p_prioritized(iface)) {
+			/* STA connection has priority over existing
+			 * P2P connection, so remove the interface. */
+			wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+			eloop_register_timeout(0, 0,
+					       wpas_p2p_group_freq_conflict,
+					       iface, NULL);
+			/* If connection in progress is P2P connection, do not
+			 * proceed for the connection. */
+			if (wpa_s == iface)
+				return -1;
+			else
+				return 0;
+		} else {
+			/* P2P connection has priority, disable the STA network
+			 */
+			wpa_supplicant_disable_network(wpa_s->global->ifaces,
+						       ssid);
+			wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+				WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+			os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+				  ETH_ALEN);
+			/* If P2P connection is in progress, continue
+			 * connecting...*/
+			if (wpa_s == iface)
+				return 0;
+			else
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+
 int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -6383,72 +7027,569 @@
 	return 0;
 }
 
-#ifdef ANDROID_P2P
-static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
 
-	wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
-	wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc,
+					     struct wpabuf *p2p)
+{
+	struct wpabuf *ret;
+	size_t wsc_len;
+
+	if (p2p == NULL) {
+		wpabuf_free(wsc);
+		wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover");
+		return NULL;
+	}
+
+	wsc_len = wsc ? wpabuf_len(wsc) : 0;
+	ret = wpabuf_alloc(2 + wsc_len + 2 + wpabuf_len(p2p));
+	if (ret == NULL) {
+		wpabuf_free(wsc);
+		wpabuf_free(p2p);
+		return NULL;
+	}
+
+	wpabuf_put_be16(ret, wsc_len);
+	if (wsc)
+		wpabuf_put_buf(ret, wsc);
+	wpabuf_put_be16(ret, wpabuf_len(p2p));
+	wpabuf_put_buf(ret, p2p);
+
+	wpabuf_free(wsc);
+	wpabuf_free(p2p);
+	wpa_hexdump_buf(MSG_DEBUG,
+			"P2P: Generated NFC connection handover message", ret);
+
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_p2p(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL) {
+			wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request");
+			return NULL;
+		}
+		ret = tmp;
+	}
+
+	return ret;
 }
 
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
-	struct wpa_ssid *ssid)
+
+static int wpas_p2p_cli_freq(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid **ssid, u8 *go_dev_addr)
 {
-	struct wpa_supplicant *iface = NULL;
-	struct p2p_data *p2p = wpa_s->global->p2p;
+	struct wpa_supplicant *iface;
 
+	if (go_dev_addr)
+		os_memset(go_dev_addr, 0, ETH_ALEN);
+	if (ssid)
+		*ssid = NULL;
 	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
-		if ((iface->current_ssid) &&
-		    (iface->current_ssid->frequency != freq) &&
-		    ((iface->p2p_group_interface) ||
-		     (iface->current_ssid->p2p_group))) {
-
-			if ((iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO)  ||
-			    (iface->current_ssid->mode == WPAS_MODE_P2P_GO)) {
-				/* Try to see whether we can move the GO. If it
-				 * is not possible, remove the GO interface
-				 */
-				if (wpa_drv_switch_channel(iface, freq) == 0) {
-					wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
-					iface->current_ssid->frequency = freq;
-					continue;
-				}
-			}
-
-			/* If GO cannot be moved or if the conflicting interface is a
-			 * P2P Client, remove the interface depending up on the connection
-			 * priority */
-			if(!wpas_is_p2p_prioritized(iface)) {
-				/* STA connection has priority over existing
-				 * P2P connection. So remove the interface */
-				wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
-						"concurrent mode frequency conflict");
-				eloop_register_timeout(0, 0, wpas_p2p_group_freq_conflict,
-						       iface, NULL);
-				/* If connection in progress is p2p connection, do not proceed for the connection */
-				if (wpa_s == iface)
-					return -1;
-				else
-					/* If connection in progress is STA connection, proceed for the connection */
-					return 0;
-			} else {
-				/* P2p connection has priority, disable the STA network*/
-				wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
-				wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
-					" id=%d", ssid->id);
-				os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
-				if (wpa_s == iface) {
-					/* p2p connection is in progress, continue connecting...*/
-					return 0;
-				}
-				else {
-					/* STA connection is in progress, do not allow to continue */
-					return -1;
-				}
-			}
-		}
+		if (iface->wpa_state < WPA_ASSOCIATING ||
+		    iface->current_ssid == NULL || iface->assoc_freq == 0 ||
+		    !iface->current_ssid->p2p_group ||
+		    iface->current_ssid->mode != WPAS_MODE_INFRA)
+			continue;
+		if (ssid)
+			*ssid = iface->current_ssid;
+		if (go_dev_addr)
+			os_memcpy(go_dev_addr, iface->go_dev_addr, ETH_ALEN);
+		return iface->assoc_freq;
 	}
 	return 0;
 }
-#endif
+
+
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+					  int ndef)
+{
+	struct wpabuf *wsc, *p2p;
+	struct wpa_ssid *ssid;
+	u8 go_dev_addr[ETH_ALEN];
+	int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request");
+		return NULL;
+	}
+
+	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+	    wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+			   &wpa_s->conf->wps_nfc_dh_privkey) < 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request");
+		return NULL;
+	}
+
+	if (cli_freq == 0) {
+		wsc = wps_build_nfc_handover_req_p2p(
+			wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey);
+	} else
+		wsc = NULL;
+	p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p, cli_freq,
+					 go_dev_addr, ssid ? ssid->ssid : NULL,
+					 ssid ? ssid->ssid_len : 0);
+
+	return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+					  int ndef, int tag)
+{
+	struct wpabuf *wsc, *p2p;
+	struct wpa_ssid *ssid;
+	u8 go_dev_addr[ETH_ALEN];
+	int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return NULL;
+
+	if (!tag && wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+	    wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+			   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+		return NULL;
+
+	if (cli_freq == 0) {
+		wsc = wps_build_nfc_handover_sel_p2p(
+			wpa_s->parent->wps,
+			tag ? wpa_s->conf->wps_nfc_dev_pw_id :
+			DEV_PW_NFC_CONNECTION_HANDOVER,
+			wpa_s->conf->wps_nfc_dh_pubkey,
+			tag ? wpa_s->conf->wps_nfc_dev_pw : NULL);
+	} else
+		wsc = NULL;
+	p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p, cli_freq,
+					 go_dev_addr, ssid ? ssid->ssid : NULL,
+					 ssid ? ssid->ssid_len : 0);
+
+	return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
+				   struct p2p_nfc_params *params)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
+		   "connection handover (freq=%d)",
+		   params->go_freq);
+
+	if (params->go_freq && params->go_ssid_len) {
+		wpa_s->p2p_wps_method = WPS_NFC;
+		wpa_s->pending_join_wps_method = WPS_NFC;
+		os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN);
+		os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr,
+			  ETH_ALEN);
+		return wpas_p2p_join_start(wpa_s, params->go_freq,
+					   params->go_ssid,
+					   params->go_ssid_len);
+	}
+
+	return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+				WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
+				params->go_freq, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
+				  struct p2p_nfc_params *params, int tag)
+{
+	int res, persistent;
+	struct wpa_ssid *ssid;
+
+	wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC "
+		   "connection handover");
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		ssid = wpa_s->current_ssid;
+		if (ssid == NULL)
+			continue;
+		if (ssid->mode != WPAS_MODE_P2P_GO)
+			continue;
+		if (wpa_s->ap_iface == NULL)
+			continue;
+		break;
+	}
+	if (wpa_s == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface");
+		return -1;
+	}
+
+	if (wpa_s->parent->p2p_oob_dev_pw_id !=
+	    DEV_PW_NFC_CONNECTION_HANDOVER &&
+	    !wpa_s->parent->p2p_oob_dev_pw) {
+		wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+		return -1;
+	}
+	res = wpas_ap_wps_add_nfc_pw(
+		wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+		wpa_s->parent->p2p_oob_dev_pw,
+		wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+		wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+	if (res)
+		return res;
+
+	if (!tag) {
+		wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation");
+		return 0;
+	}
+
+	if (!params->peer ||
+	    !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE))
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR
+		   " to join", MAC2STR(params->peer->p2p_device_addr));
+
+	wpa_s->global->p2p_invite_group = wpa_s;
+	persistent = ssid->p2p_persistent_group &&
+		wpas_p2p_get_persistent(wpa_s->parent,
+					params->peer->p2p_device_addr,
+					ssid->ssid, ssid->ssid_len);
+	wpa_s->parent->pending_invite_ssid_id = -1;
+
+	return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
+			  P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
+			  ssid->ssid, ssid->ssid_len, ssid->frequency,
+			  wpa_s->global->p2p_dev_addr, persistent, 0,
+			  wpa_s->parent->p2p_oob_dev_pw_id);
+}
+
+
+static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
+				    struct p2p_nfc_params *params,
+				    int forced_freq)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC "
+		   "connection handover");
+	return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+				WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
+				forced_freq, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
+				    struct p2p_nfc_params *params,
+				    int forced_freq)
+{
+	int res;
+
+	wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC "
+		   "connection handover");
+	res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+			       WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
+			       forced_freq, -1, 0, 1, 1);
+	if (res)
+		return res;
+
+	res = wpas_p2p_listen(wpa_s, 60);
+	if (res) {
+		p2p_unauthorize(wpa_s->global->p2p,
+				params->peer->p2p_device_addr);
+	}
+
+	return res;
+}
+
+
+static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s,
+					    const struct wpabuf *data,
+					    int sel, int tag, int forced_freq)
+{
+	const u8 *pos, *end;
+	u16 len, id;
+	struct p2p_nfc_params params;
+	int res;
+
+	os_memset(&params, 0, sizeof(params));
+	params.sel = sel;
+
+	wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data);
+
+	pos = wpabuf_head(data);
+	end = pos + wpabuf_len(data);
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC "
+			   "attributes");
+		return -1;
+	}
+	len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (pos + len > end) {
+		wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
+			   "attributes");
+		return -1;
+	}
+	params.wsc_attr = pos;
+	params.wsc_len = len;
+	pos += len;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P "
+			   "attributes");
+		return -1;
+	}
+	len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (pos + len > end) {
+		wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
+			   "attributes");
+		return -1;
+	}
+	params.p2p_attr = pos;
+	params.p2p_len = len;
+	pos += len;
+
+	wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes",
+		    params.wsc_attr, params.wsc_len);
+	wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes",
+		    params.p2p_attr, params.p2p_len);
+	if (pos < end) {
+		wpa_hexdump(MSG_DEBUG,
+			    "P2P: Ignored extra data after P2P attributes",
+			    pos, end - pos);
+	}
+
+	res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, &params);
+	if (res)
+		return res;
+
+	if (params.next_step == NO_ACTION)
+		return 0;
+
+	if (params.next_step == BOTH_GO) {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_BOTH_GO "peer=" MACSTR,
+			MAC2STR(params.peer->p2p_device_addr));
+		return 0;
+	}
+
+	if (params.next_step == PEER_CLIENT) {
+		if (!is_zero_ether_addr(params.go_dev_addr)) {
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+				"peer=" MACSTR " freq=%d go_dev_addr=" MACSTR
+				" ssid=\"%s\"",
+				MAC2STR(params.peer->p2p_device_addr),
+				params.go_freq,
+				MAC2STR(params.go_dev_addr),
+				wpa_ssid_txt(params.go_ssid,
+					     params.go_ssid_len));
+		} else {
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+				"peer=" MACSTR " freq=%d",
+				MAC2STR(params.peer->p2p_device_addr),
+				params.go_freq);
+		}
+		return 0;
+	}
+
+	if (wpas_p2p_cli_freq(wpa_s, NULL, NULL)) {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_WHILE_CLIENT "peer="
+			MACSTR, MAC2STR(params.peer->p2p_device_addr));
+		return 0;
+	}
+
+	wpabuf_free(wpa_s->p2p_oob_dev_pw);
+	wpa_s->p2p_oob_dev_pw = NULL;
+
+	if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+		wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw "
+			   "received");
+		return -1;
+	}
+
+	id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN);
+	wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id);
+	wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash",
+		    params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+	os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash,
+		  params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+	wpa_s->p2p_peer_oob_pk_hash_known = 1;
+
+	if (tag) {
+		if (id < 0x10) {
+			wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
+				   "peer OOB Device Password Id %u", id);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB "
+			   "Device Password Id %u", id);
+		wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password",
+				params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+				params.oob_dev_pw_len -
+				WPS_OOB_PUBKEY_HASH_LEN - 2);
+		wpa_s->p2p_oob_dev_pw_id = id;
+		wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy(
+			params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+			params.oob_dev_pw_len -
+			WPS_OOB_PUBKEY_HASH_LEN - 2);
+		if (wpa_s->p2p_oob_dev_pw == NULL)
+			return -1;
+
+		if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+		    wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+				   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+			return -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake "
+			   "without Device Password");
+		wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+	}
+
+	switch (params.next_step) {
+	case NO_ACTION:
+	case BOTH_GO:
+	case PEER_CLIENT:
+		/* already covered above */
+		return 0;
+	case JOIN_GROUP:
+		return wpas_p2p_nfc_join_group(wpa_s, &params);
+	case AUTH_JOIN:
+		return wpas_p2p_nfc_auth_join(wpa_s, &params, tag);
+	case INIT_GO_NEG:
+		return wpas_p2p_nfc_init_go_neg(wpa_s, &params, forced_freq);
+	case RESP_GO_NEG:
+		/* TODO: use own OOB Dev Pw */
+		return wpas_p2p_nfc_resp_go_neg(wpa_s, &params, forced_freq);
+	}
+
+	return -1;
+}
+
+
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+			     const struct wpabuf *data, int forced_freq)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	return wpas_p2p_nfc_connection_handover(wpa_s, data, 1, 1, forced_freq);
+}
+
+
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+				 const struct wpabuf *req,
+				 const struct wpabuf *sel, int forced_freq)
+{
+	struct wpabuf *tmp;
+	int ret;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported");
+
+	wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req",
+			  wpabuf_head(req), wpabuf_len(req));
+	wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel",
+			  wpabuf_head(sel), wpabuf_len(sel));
+	if (forced_freq)
+		wpa_printf(MSG_DEBUG, "NFC: Forced freq %d", forced_freq);
+	tmp = ndef_parse_p2p(init ? sel : req);
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF");
+		return -1;
+	}
+
+	ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0,
+					       forced_freq);
+	wpabuf_free(tmp);
+
+	return ret;
+}
+
+
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
+{
+	const u8 *if_addr;
+	int go_intent = wpa_s->conf->p2p_go_intent;
+	struct wpa_supplicant *iface;
+
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+
+	if (!enabled) {
+		wpa_printf(MSG_DEBUG, "P2P: Disable use of own NFC Tag");
+		for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+		{
+			if (!iface->ap_iface)
+				continue;
+			hostapd_wps_nfc_token_disable(iface->ap_iface->bss[0]);
+		}
+		p2p_set_authorized_oob_dev_pw_id(wpa_s->global->p2p, 0,
+						 0, NULL);
+		if (wpa_s->p2p_nfc_tag_enabled)
+			wpas_p2p_remove_pending_group_interface(wpa_s);
+		wpa_s->p2p_nfc_tag_enabled = 0;
+		return 0;
+	}
+
+	if (wpa_s->global->p2p_disabled)
+		return -1;
+
+	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+	    wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+	    wpa_s->conf->wps_nfc_dev_pw == NULL ||
+	    wpa_s->conf->wps_nfc_dev_pw_id < 0x10) {
+		wpa_printf(MSG_DEBUG, "P2P: NFC password token not configured "
+			   "to allow static handover cases");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Enable use of own NFC Tag");
+
+	wpa_s->p2p_oob_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+	wpabuf_free(wpa_s->p2p_oob_dev_pw);
+	wpa_s->p2p_oob_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+	if (wpa_s->p2p_oob_dev_pw == NULL)
+		return -1;
+	wpa_s->p2p_peer_oob_pk_hash_known = 0;
+
+	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+
+	if (wpa_s->create_p2p_iface) {
+		enum wpa_driver_if_type iftype;
+		/* Prepare to add a new interface for the group */
+		iftype = WPA_IF_P2P_GROUP;
+		if (go_intent == 15)
+			iftype = WPA_IF_P2P_GO;
+		if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+				   "interface for the group");
+			return -1;
+		}
+
+		if_addr = wpa_s->pending_interface_addr;
+	} else
+		if_addr = wpa_s->own_addr;
+
+	wpa_s->p2p_nfc_tag_enabled = enabled;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		struct hostapd_data *hapd;
+		if (iface->ap_iface == NULL)
+			continue;
+		hapd = iface->ap_iface->bss[0];
+		wpabuf_free(hapd->conf->wps_nfc_dh_pubkey);
+		hapd->conf->wps_nfc_dh_pubkey =
+			wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+		wpabuf_free(hapd->conf->wps_nfc_dh_privkey);
+		hapd->conf->wps_nfc_dh_privkey =
+			wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+		wpabuf_free(hapd->conf->wps_nfc_dev_pw);
+		hapd->conf->wps_nfc_dev_pw =
+			wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+		hapd->conf->wps_nfc_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+
+		if (hostapd_wps_nfc_token_enable(iface->ap_iface->bss[0]) < 0) {
+			wpa_dbg(iface, MSG_DEBUG,
+				"P2P: Failed to enable NFC Tag for GO");
+		}
+	}
+	p2p_set_authorized_oob_dev_pw_id(
+		wpa_s->global->p2p, wpa_s->conf->wps_nfc_dev_pw_id, go_intent,
+		if_addr);
+
+	return 0;
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 65ccbf9..d3d36b1 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -24,22 +24,21 @@
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join,
 		     int auth, int go_intent, int freq, int persistent_id,
-		     int pd, int ht40);
+		     int pd, int ht40, int vht);
 void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 				   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq);
-#ifdef ANDROID_P2P
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
                                           int freq, struct wpa_ssid *ssid);
-#endif
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-		       int freq, int ht40);
+		       int freq, int ht40, int vht);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
-				  int freq, int ht40,
-				  const struct p2p_channels *channels);
+				  int force_freq, int neg_freq, int ht40,
+				  int vht, const struct p2p_channels *channels,
+				  int connection_timeout);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid);
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
@@ -75,22 +74,7 @@
 			u8 category, const u8 *data, size_t len, int freq);
 void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
 void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
-void wpas_dev_found(void *ctx, const u8 *addr,
-		    const struct p2p_peer_info *info,
-		    int new_device);
 void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
-			const u8 *dev_addr, const u8 *pri_dev_type,
-			const char *dev_name, u16 supp_config_methods,
-			u8 dev_capab, u8 group_capab, const u8 *group_id,
-			size_t group_id_len);
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
-		     u16 update_indic, const u8 *tlvs, size_t tlvs_len);
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
-		      const u8 *tlvs, size_t tlvs_len);
 u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
 			const struct wpabuf *tlvs);
 u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
@@ -114,7 +98,7 @@
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int ht40, int pref_freq);
+		    int ht40, int vht, int pref_freq);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 			  const u8 *peer_addr, const u8 *go_dev_addr);
 void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -144,6 +128,7 @@
 int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
 void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 			 struct wps_event_fail *fail);
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
 int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
 void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
 			      struct wpa_ssid *ssid);
@@ -155,22 +140,29 @@
 int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+			      struct hostapd_hw_modes *mode, u8 channel);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
 void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
 			 const u8 *p2p_dev_addr,
 			 const u8 *psk, size_t psk_len);
 void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
 			    int iface_addr);
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+					  int ndef);
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+					  int ndef, int tag);
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+			     const struct wpabuf *data, int forced_freq);
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+				 const struct wpabuf *req,
+				 const struct wpabuf *sel, int forced_freq);
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
 
 #ifdef CONFIG_P2P
-void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
 int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
 void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
 #else /* CONFIG_P2P */
-static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
-{
-}
-
 static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
 {
 	return 0;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index ff2ae74..ed57085 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -27,9 +27,6 @@
 #include "drivers/driver.h"
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
 struct wpa_driver_ops *wpa_drivers[] = { NULL };
 
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index a0f51d0..6c742d6 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Scanning
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -141,71 +141,43 @@
 }
 
 
-static int int_array_len(const int *a)
+static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
 {
-	int i;
-	for (i = 0; a && a[i]; i++)
-		;
-	return i;
-}
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct wpa_driver_scan_params *params = work->ctx;
+	int ret;
 
-
-static void int_array_concat(int **res, const int *a)
-{
-	int reslen, alen, i;
-	int *n;
-
-	reslen = int_array_len(*res);
-	alen = int_array_len(a);
-
-	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
-	if (n == NULL) {
-		os_free(*res);
-		*res = NULL;
-		return;
-	}
-	for (i = 0; i <= alen; i++)
-		n[reslen + i] = a[i];
-	*res = n;
-}
-
-
-static int freq_cmp(const void *a, const void *b)
-{
-	int _a = *(int *) a;
-	int _b = *(int *) b;
-
-	if (_a == 0)
-		return 1;
-	if (_b == 0)
-		return -1;
-	return _a - _b;
-}
-
-
-static void int_array_sort_unique(int *a)
-{
-	int alen;
-	int i, j;
-
-	if (a == NULL)
-		return;
-
-	alen = int_array_len(a);
-	qsort(a, alen, sizeof(int), freq_cmp);
-
-	i = 0;
-	j = 1;
-	while (a[i] && a[j]) {
-		if (a[i] == a[j]) {
-			j++;
-			continue;
+	if (deinit) {
+		if (!work->started) {
+			wpa_scan_free_params(params);
+			return;
 		}
-		a[++i] = a[j++];
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+		wpas_notify_scan_done(wpa_s, 0);
+		wpa_s->scan_work = NULL;
+		return;
 	}
-	if (a[i])
-		i++;
-	a[i] = 0;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+
+	if (wpa_s->clear_driver_scan_cache)
+		params->only_new_results = 1;
+	ret = wpa_drv_scan(wpa_s, params);
+	wpa_scan_free_params(params);
+	work->ctx = NULL;
+	if (ret) {
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+		wpas_notify_scan_done(wpa_s, 0);
+		radio_work_done(work);
+		return;
+	}
+
+	os_get_reltime(&wpa_s->scan_trigger_time);
+	wpa_s->scan_runs++;
+	wpa_s->normal_scans++;
+	wpa_s->own_scan_requested = 1;
+	wpa_s->clear_driver_scan_cache = 0;
+	wpa_s->scan_work = work;
 }
 
 
@@ -218,21 +190,24 @@
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
 				struct wpa_driver_scan_params *params)
 {
-	int ret;
+	struct wpa_driver_scan_params *ctx;
 
-	wpa_supplicant_notify_scanning(wpa_s, 1);
-
-	ret = wpa_drv_scan(wpa_s, params);
-	if (ret) {
-		wpa_supplicant_notify_scanning(wpa_s, 0);
-		wpas_notify_scan_done(wpa_s, 0);
-	} else {
-		os_get_time(&wpa_s->scan_trigger_time);
-		wpa_s->scan_runs++;
-		wpa_s->normal_scans++;
+	if (wpa_s->scan_work) {
+		wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
+		return -1;
 	}
 
-	return ret;
+	ctx = wpa_scan_clone_params(params);
+	if (ctx == NULL)
+		return -1;
+
+	if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+	{
+		wpa_scan_free_params(ctx);
+		return -1;
+	}
+
+	return 0;
 }
 
 
@@ -260,10 +235,9 @@
 }
 
 
-static int
-wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params,
-				int interval)
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_scan_params *params,
+				    int interval)
 {
 	int ret;
 
@@ -271,15 +245,14 @@
 	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
 	if (ret)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
-	else {
+	else
 		wpa_s->sched_scanning = 1;
-	}
 
 	return ret;
 }
 
 
-static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
 {
 	int ret;
 
@@ -367,7 +340,8 @@
 		if (params->freqs)
 			params->freqs[0] = wpa_s->wps_freq;
 		wpa_s->after_wps--;
-	}
+	} else if (wpa_s->after_wps)
+		wpa_s->after_wps--;
 
 	if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
 	{
@@ -546,7 +520,6 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
-	enum scan_req_type scan_req = NORMAL_SCAN_REQ;
 	int ret;
 	struct wpabuf *extra_ie = NULL;
 	struct wpa_driver_scan_params params;
@@ -554,30 +527,36 @@
 	size_t max_ssids;
 	enum wpa_states prev_state;
 
+	if (wpa_s->pno || wpa_s->pno_sched_pending) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
+		return;
+	}
+
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
-		wpas_p2p_continue_after_scan(wpa_s);
 		return;
 	}
 
 	if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
 		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-		wpas_p2p_continue_after_scan(wpa_s);
 		return;
 	}
-#ifdef ANDROID
+
 	if (wpa_s->scanning) {
-		/* If we are already in scanning state, we shall ignore this new scan request*/
-		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - already scanning");
+		/*
+		 * If we are already in scanning state, we shall reschedule the
+		 * the incoming scan request.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
 		return;
 	}
-#endif
+
 	if (!wpa_supplicant_enabled_networks(wpa_s) &&
 	    wpa_s->scan_req == NORMAL_SCAN_REQ) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-		wpas_p2p_continue_after_scan(wpa_s);
 		return;
 	}
 
@@ -595,19 +574,10 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s)) {
-		if (wpa_s->sta_scan_pending &&
-		    wpas_p2p_in_progress(wpa_s) == 2 &&
-		    wpa_s->global->p2p_cb_on_scan_complete) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
-				"mode scan during P2P search");
-		} else {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
-				"while P2P operation is in progress");
-			wpa_s->sta_scan_pending = 1;
-			wpa_supplicant_req_scan(wpa_s, 5, 0);
-			return;
-		}
+	if (wpas_p2p_in_progress(wpa_s)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
+		wpa_supplicant_req_scan(wpa_s, 5, 0);
+		return;
 	}
 #endif /* CONFIG_P2P */
 
@@ -619,7 +589,7 @@
 			max_ssids = WPAS_MAX_SCAN_SSIDS;
 	}
 
-	scan_req = wpa_s->scan_req;
+	wpa_s->last_scan_req = wpa_s->scan_req;
 	wpa_s->scan_req = NORMAL_SCAN_REQ;
 
 	os_memset(&params, 0, sizeof(params));
@@ -637,7 +607,8 @@
 		goto scan;
 	}
 
-	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_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;
@@ -654,8 +625,9 @@
 #ifdef CONFIG_P2P
 	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
 	    wpa_s->go_params) {
-		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
-			   "P2P group formation");
+		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
+			   wpa_s->p2p_in_provisioning,
+			   wpa_s->show_group_started);
 		params.ssids[0].ssid = wpa_s->go_params->ssid;
 		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
 		params.num_ssids = 1;
@@ -675,19 +647,18 @@
 		}
 	}
 
-	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
+	if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
+	    wpa_s->conf->ap_scan == 2) {
 		wpa_s->connect_without_scan = NULL;
 		wpa_s->prev_scan_wildcard = 0;
 		wpa_supplicant_assoc_try(wpa_s, ssid);
 		return;
-#ifndef ANDROID
 	} else if (wpa_s->conf->ap_scan == 2) {
 		/*
 		 * User-initiated scan request in ap_scan == 2; scan with
 		 * wildcard SSID.
 		 */
 		ssid = NULL;
-#endif
 	} else {
 		struct wpa_ssid *start = ssid, *tssid;
 		int freqs_set = 0;
@@ -755,6 +726,9 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
 			"the scan request");
 		params.num_ssids++;
+	} else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+		   wpa_s->manual_scan_passive && params.num_ssids == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
 	} else {
 		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
 		params.num_ssids++;
@@ -768,6 +742,17 @@
 	wpa_supplicant_optimize_freqs(wpa_s, &params);
 	extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
+	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+	    wpa_s->manual_scan_only_new)
+		params.only_new_results = 1;
+
+	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
+	    wpa_s->manual_scan_freqs) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
+		params.freqs = wpa_s->manual_scan_freqs;
+		wpa_s->manual_scan_freqs = NULL;
+	}
+
 	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
 			"generated frequency list");
@@ -833,7 +818,8 @@
 	 * station interface when we are not configured to prefer station
 	 * connection and a concurrent operation is already in process.
 	 */
-	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+	if (wpa_s->scan_for_connection &&
+	    wpa_s->last_scan_req == NORMAL_SCAN_REQ &&
 	    !scan_params->freqs && !params.freqs &&
 	    wpas_is_p2p_prioritized(wpa_s) &&
 	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
@@ -855,6 +841,13 @@
 
 	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
 
+	if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
+	    !wpa_s->manual_scan_freqs) {
+		/* Restore manual_scan_freqs for the next attempt */
+		wpa_s->manual_scan_freqs = params.freqs;
+		params.freqs = NULL;
+	}
+
 	wpabuf_free(extra_ie);
 	os_free(params.freqs);
 	os_free(params.filter_ssids);
@@ -864,7 +857,7 @@
 		if (prev_state != wpa_s->wpa_state)
 			wpa_supplicant_set_state(wpa_s, prev_state);
 		/* Restore scan_req since we will try to scan again */
-		wpa_s->scan_req = scan_req;
+		wpa_s->scan_req = wpa_s->last_scan_req;
 		wpa_supplicant_req_scan(wpa_s, 1, 0);
 	} else {
 		wpa_s->scan_for_connection = 0;
@@ -874,7 +867,7 @@
 
 void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
 {
-	struct os_time remaining, new_int;
+	struct os_reltime remaining, new_int;
 	int cancelled;
 
 	cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
@@ -882,13 +875,15 @@
 
 	new_int.sec = sec;
 	new_int.usec = 0;
-	if (cancelled && os_time_before(&remaining, &new_int)) {
+	if (cancelled && os_reltime_before(&remaining, &new_int)) {
 		new_int.sec = remaining.sec;
 		new_int.usec = remaining.usec;
 	}
 
-	eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
-			       wpa_s, NULL);
+	if (cancelled) {
+		eloop_register_timeout(new_int.sec, new_int.usec,
+				       wpa_supplicant_scan, wpa_s, NULL);
+	}
 	wpa_s->scan_interval = sec;
 }
 
@@ -904,34 +899,19 @@
  */
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 {
-#ifndef ANDROID
-	/* If there's at least one network that should be specifically scanned
-	 * then don't cancel the scan and reschedule.  Some drivers do
-	 * background scanning which generates frequent scan results, and that
-	 * causes the specific SSID scan to get continually pushed back and
-	 * never happen, which causes hidden APs to never get probe-scanned.
-	 */
-	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
-	    wpa_s->conf->ap_scan == 1) {
-		struct wpa_ssid *ssid = wpa_s->conf->ssid;
-
-		while (ssid) {
-			if (!wpas_network_disabled(wpa_s, ssid) &&
-			    ssid->scan_ssid)
-				break;
-			ssid = ssid->next;
-		}
-		if (ssid) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
-			        "ensure that specific SSID scans occur");
-			return;
-		}
+	int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+					NULL);
+	if (res == 1) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
+			sec, usec);
+	} else if (res == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
+			sec, usec);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
+			sec, usec);
+		eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
 	}
-#endif
-	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
-		sec, usec);
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
 }
 
 
@@ -1143,6 +1123,9 @@
 		params.extra_ies_len = wpabuf_len(extra_ie);
 	}
 
+	if (wpa_s->conf->filter_rssi)
+		params.filter_rssi = wpa_s->conf->filter_rssi;
+
 	scan_params = &params;
 
 scan:
@@ -1203,10 +1186,6 @@
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	wpas_p2p_continue_after_scan(wpa_s);
-#ifdef ANDROID
-	wpa_supplicant_notify_scanning(wpa_s, 0);
-#endif
 }
 
 
@@ -1345,6 +1324,43 @@
 
 
 /**
+ * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ *
+ * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+					 u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	if (res->beacon_ie_len == 0)
+		return NULL;
+
+	pos = (const u8 *) (res + 1);
+	pos += res->ie_len;
+	end = pos + res->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
  * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
  * @res: Scan result entry
  * @vendor_type: Vendor type (four octets starting the IE payload)
@@ -1632,12 +1648,12 @@
 		 * Make sure we have a valid timestamp if the driver wrapper
 		 * does not set this.
 		 */
-		os_get_time(&scan_res->fetch_time);
+		os_get_reltime(&scan_res->fetch_time);
 	}
 	filter_scan_res(wpa_s, scan_res);
 
 #ifdef CONFIG_WPS
-	if (wpas_wps_in_progress(wpa_s)) {
+	if (wpas_wps_searching(wpa_s)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
 			"provisioning rules");
 		compar = wpa_scan_result_wps_compar;
@@ -1689,9 +1705,21 @@
 		       struct wpa_scan_results *scan_res)
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
-	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+	    wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
+			     wpa_s->manual_scan_id);
+		wpa_s->manual_scan_use_id = 0;
+	} else {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	}
 	wpas_notify_scan_results(wpa_s);
 	wpas_notify_scan_done(wpa_s, 1);
+	if (wpa_s->scan_work) {
+		struct wpa_radio_work *work = wpa_s->scan_work;
+		wpa_s->scan_work = NULL;
+		radio_work_done(work);
+	}
 }
 
 
@@ -1699,3 +1727,83 @@
 {
 	return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
 }
+
+
+struct wpa_driver_scan_params *
+wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
+{
+	struct wpa_driver_scan_params *params;
+	size_t i;
+	u8 *n;
+
+	params = os_zalloc(sizeof(*params));
+	if (params == NULL)
+		return NULL;
+
+	for (i = 0; i < src->num_ssids; i++) {
+		if (src->ssids[i].ssid) {
+			n = os_malloc(src->ssids[i].ssid_len);
+			if (n == NULL)
+				goto failed;
+			os_memcpy(n, src->ssids[i].ssid,
+				  src->ssids[i].ssid_len);
+			params->ssids[i].ssid = n;
+			params->ssids[i].ssid_len = src->ssids[i].ssid_len;
+		}
+	}
+	params->num_ssids = src->num_ssids;
+
+	if (src->extra_ies) {
+		n = os_malloc(src->extra_ies_len);
+		if (n == NULL)
+			goto failed;
+		os_memcpy(n, src->extra_ies, src->extra_ies_len);
+		params->extra_ies = n;
+		params->extra_ies_len = src->extra_ies_len;
+	}
+
+	if (src->freqs) {
+		int len = int_array_len(src->freqs);
+		params->freqs = os_malloc((len + 1) * sizeof(int));
+		if (params->freqs == NULL)
+			goto failed;
+		os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int));
+	}
+
+	if (src->filter_ssids) {
+		params->filter_ssids = os_malloc(sizeof(*params->filter_ssids) *
+						 src->num_filter_ssids);
+		if (params->filter_ssids == NULL)
+			goto failed;
+		os_memcpy(params->filter_ssids, src->filter_ssids,
+			  sizeof(*params->filter_ssids) *
+			  src->num_filter_ssids);
+		params->num_filter_ssids = src->num_filter_ssids;
+	}
+
+	params->filter_rssi = src->filter_rssi;
+	params->p2p_probe = src->p2p_probe;
+	params->only_new_results = src->only_new_results;
+
+	return params;
+
+failed:
+	wpa_scan_free_params(params);
+	return NULL;
+}
+
+
+void wpa_scan_free_params(struct wpa_driver_scan_params *params)
+{
+	size_t i;
+
+	if (params == NULL)
+		return;
+
+	for (i = 0; i < params->num_ssids; i++)
+		os_free((u8 *) params->ssids[i].ssid);
+	os_free((u8 *) params->extra_ies);
+	os_free(params->freqs);
+	os_free(params->filter_ssids);
+	os_free(params);
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2144787..e4c8989 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,8 @@
 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
 				  u32 vendor_type);
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+					 u32 vendor_type);
 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
 					     u32 vendor_type);
 int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
@@ -37,5 +39,12 @@
 void scan_only_handler(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
 int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_scan_params *params,
+				    int interval);
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
+struct wpa_driver_scan_params *
+wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
+void wpa_scan_free_params(struct wpa_driver_scan_params *params);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 925d132..e712ac4 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - SME
- * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -46,7 +46,7 @@
 {
 	int i;
 	for (i = 0; i < idx; i++) {
-		if (array[i] == -1)
+		if (array[i] <= 0)
 			return 0;
 	}
 	return 1;
@@ -56,9 +56,9 @@
 static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
 {
 	int *groups = wpa_s->conf->sae_groups;
-	int default_groups[] = { 19, 20, 21, 25, 26 };
+	int default_groups[] = { 19, 20, 21, 25, 26, 0 };
 
-	if (!groups)
+	if (!groups || groups[0] <= 0)
 		groups = default_groups;
 
 	/* Configuration may have changed, so validate current index */
@@ -157,6 +157,7 @@
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
 			"the network");
+		wpas_connect_work_done(wpa_s);
 		return;
 	}
 
@@ -244,6 +245,7 @@
 					      &wpa_s->sme.assoc_req_ie_len)) {
 			wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
 				"key management and encryption suites");
+			wpas_connect_work_done(wpa_s);
 			return;
 		}
 	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -263,6 +265,7 @@
 			wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
 				"key management and encryption suites (no "
 				"scan results)");
+			wpas_connect_work_done(wpa_s);
 			return;
 		}
 #ifdef CONFIG_WPS
@@ -386,8 +389,10 @@
 							 bss->bssid);
 		else
 			resp = sme_auth_build_sae_confirm(wpa_s);
-		if (resp == NULL)
+		if (resp == NULL) {
+			wpas_connect_work_done(wpa_s);
 			return;
+		}
 		params.sae_data = wpabuf_head(resp);
 		params.sae_data_len = wpabuf_len(resp);
 		wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
@@ -417,6 +422,7 @@
 		wpas_connection_failed(wpa_s, bss->bssid);
 		wpa_supplicant_mark_disassoc(wpa_s);
 		wpabuf_free(resp);
+		wpas_connect_work_done(wpa_s);
 		return;
 	}
 
@@ -432,14 +438,59 @@
 }
 
 
+static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_connect_work *cwork = work->ctx;
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+
+	if (deinit) {
+		if (work->started)
+			wpa_s->connect_work = NULL;
+
+		wpas_connect_work_free(cwork);
+		return;
+	}
+
+	wpa_s->connect_work = work;
+
+	if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
+		wpas_connect_work_done(wpa_s);
+		return;
+	}
+
+	sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
+}
+
+
 void sme_authenticate(struct wpa_supplicant *wpa_s,
 		      struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
+	struct wpa_connect_work *cwork;
+
+	if (bss == NULL || ssid == NULL)
+		return;
+	if (wpa_s->connect_work) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist");
+		return;
+	}
+
+	cwork = os_zalloc(sizeof(*cwork));
+	if (cwork == NULL)
+		return;
+	cwork->bss = bss;
+	cwork->ssid = ssid;
+	cwork->sme = 1;
+
 #ifdef CONFIG_SAE
 	wpa_s->sme.sae.state = SAE_NOTHING;
 	wpa_s->sme.sae.send_confirm = 0;
+	wpa_s->sme.sae_group_index = 0;
 #endif /* CONFIG_SAE */
-	sme_send_authentication(wpa_s, bss, ssid, 1);
+
+	if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1,
+			   sme_auth_start_cb, cwork) < 0)
+		wpas_connect_work_free(cwork);
 }
 
 
@@ -482,15 +533,18 @@
 		return -1;
 
 	if (auth_transaction == 1) {
+		int *groups = wpa_s->conf->sae_groups;
+
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
 		if (wpa_s->current_bss == NULL ||
 		    wpa_s->current_ssid == NULL)
 			return -1;
 		if (wpa_s->sme.sae.state != SAE_COMMITTED)
 			return -1;
+		if (groups && groups[0] <= 0)
+			groups = NULL;
 		if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
-				     wpa_s->conf->sae_groups) !=
-		    WLAN_STATUS_SUCCESS)
+				     groups) != WLAN_STATUS_SUCCESS)
 			return -1;
 
 		if (sae_process_commit(&wpa_s->sme.sae) < 0) {
@@ -585,6 +639,8 @@
 			return;
 		}
 
+		wpas_connect_work_done(wpa_s);
+
 		switch (data->auth.auth_type) {
 		case WLAN_AUTH_OPEN:
 			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
@@ -647,9 +703,8 @@
 	params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
 		wpa_s->sme.assoc_req_ie : NULL;
 	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
-	params.pairwise_suite =
-		wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
-	params.group_suite = wpa_cipher_to_suite_driver(wpa_s->group_cipher);
+	params.pairwise_suite = wpa_s->pairwise_cipher;
+	params.group_suite = wpa_s->group_cipher;
 #ifdef CONFIG_HT_OVERRIDES
 	os_memset(&htcaps, 0, sizeof(htcaps));
 	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
@@ -1147,9 +1202,9 @@
 static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
 {
 	u32 tu;
-	struct os_time now, passed;
-	os_get_time(&now);
-	os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
+	struct os_reltime now, passed;
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed);
 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
 	if (sa_query_max_timeout < tu) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
@@ -1199,7 +1254,7 @@
 		return;
 	if (wpa_s->sme.sa_query_count == 0) {
 		/* Starting a new SA Query procedure */
-		os_get_time(&wpa_s->sme.sa_query_start);
+		os_get_reltime(&wpa_s->sme.sa_query_start);
 	}
 	trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
 	wpa_s->sme.sa_query_trans_id = nbuf;
diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c
index 484a406..39971f2 100644
--- a/wpa_supplicant/tests/test_wpa.c
+++ b/wpa_supplicant/tests/test_wpa.c
@@ -17,10 +17,6 @@
 #include "ap/wpa_auth.h"
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
-
 struct wpa {
 	u8 auth_addr[ETH_ALEN];
 	u8 supp_addr[ETH_ALEN];
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index 92ca536..8435b63 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -16,6 +16,9 @@
 #include "wifi_display.h"
 
 
+#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
+
+
 int wifi_display_init(struct wpa_global *global)
 {
 	global->wifi_display = 1;
@@ -38,6 +41,9 @@
 	struct wpabuf *ie, *buf;
 	size_t len, plen;
 
+	if (global->p2p == NULL)
+		return 0;
+
 	wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
 
 	if (!global->wifi_display) {
@@ -249,3 +255,41 @@
 				1,
 				wpabuf_len(global->wfd_subelem[subelem]) - 1);
 }
+
+
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
+{
+	char *subelem = NULL;
+	const u8 *buf;
+	size_t buflen;
+	size_t i = 0;
+	u16 elen;
+
+	if (!wfd_subelems)
+		return NULL;
+
+	buf = wpabuf_head_u8(wfd_subelems);
+	if (!buf)
+		return NULL;
+
+	buflen = wpabuf_len(wfd_subelems);
+
+	while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
+		elen = WPA_GET_BE16(buf + i + 1);
+
+		if (buf[i] == id) {
+			subelem = os_zalloc(2 * elen + 1);
+			if (!subelem)
+				return NULL;
+			wpa_snprintf_hex(subelem, 2 * elen + 1,
+					 buf + i +
+					 WIFI_DISPLAY_SUBELEM_HEADER_LEN,
+					 elen);
+			break;
+		}
+
+		i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
+	}
+
+	return subelem;
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
index b75d4f2..7554817 100644
--- a/wpa_supplicant/wifi_display.h
+++ b/wpa_supplicant/wifi_display.h
@@ -16,5 +16,6 @@
 int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
 int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
 			     char *buf, size_t buflen);
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
 
 #endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4f8d895..65b2783 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -181,7 +181,7 @@
 	/* Install GTK/IGTK */
 
 	/* point to key data field */
-	ptr = (u8 *) frm + 1 + 1 + 2;
+	ptr = (u8 *) frm + 1 + 2;
 	end = ptr + key_len_total;
 	wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
 
@@ -237,16 +237,16 @@
 	 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
 	 * WNM-Sleep Mode IE | TFS Response IE
 	 */
-	u8 *pos = (u8 *) frm; /* point to action field */
+	u8 *pos = (u8 *) frm; /* point to payload after the action field */
 	u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
 	struct wnm_sleep_element *wnmsleep_ie = NULL;
 	/* multiple TFS Resp IE (assuming consecutive) */
 	u8 *tfsresp_ie_start = NULL;
 	u8 *tfsresp_ie_end = NULL;
 
-	wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
-		   frm[0], frm[1], key_len_total);
-	pos += 4 + key_len_total;
+	wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
+		   frm[0], key_len_total);
+	pos += 3 + key_len_total;
 	if (pos > frm + len) {
 		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
 		return;
@@ -473,6 +473,10 @@
 	if (scan_res == NULL || num_neigh_rep == 0)
 		return 0;
 
+	wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
+		   MAC2STR(wpa_s->bssid),
+		   wpa_s->current_bss ? wpa_s->current_bss->level : 0);
+
 	for (i = 0; i < num_neigh_rep; i++) {
 		for (j = 0; j < scan_res->num; j++) {
 			/* Check for a better RSSI AP */
@@ -483,8 +487,16 @@
 				/* Got a BSSID with better RSSI value */
 				os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
 					  ETH_ALEN);
+				wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR
+					   " with better scan RSSI %d",
+					   MAC2STR(scan_res->res[j]->bssid),
+					   scan_res->res[j]->level);
 				return 1;
 			}
+			wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR
+				   " RSSI %d", j,
+				   MAC2STR(scan_res->res[j]->bssid),
+				   scan_res->res[j]->level);
 		}
 	}
 
@@ -521,6 +533,14 @@
 	if (target_bssid) {
 		os_memcpy(pos, target_bssid, ETH_ALEN);
 		pos += ETH_ALEN;
+	} else if (status == WNM_BSS_TM_ACCEPT) {
+		/*
+		 * P802.11-REVmc clarifies that the Target BSSID field is always
+		 * present when status code is zero, so use a fake value here if
+		 * no BSSID is yet known.
+		 */
+		os_memset(pos, 0, ETH_ALEN);
+		pos += ETH_ALEN;
 	}
 
 	len = pos - (u8 *) &mgmt->u.action.category;
@@ -562,7 +582,7 @@
 			wnm_send_bss_transition_mgmt_resp(wpa_s,
 						  wpa_s->wnm_dialog_token,
 						  WNM_BSS_TM_ACCEPT,
-						  0, NULL);
+						  0, bssid);
 		}
 
 		wpa_s->reassociate = 1;
@@ -717,7 +737,7 @@
 					   WLAN_FC_STYPE_ACTION);
 	mgmt->u.action.category = WLAN_ACTION_WNM;
 	mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
-	mgmt->u.action.u.bss_tm_query.dialog_token = 0;
+	mgmt->u.action.u.bss_tm_query.dialog_token = 1;
 	mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
 	pos = mgmt->u.action.u.bss_tm_query.variable;
 
@@ -732,22 +752,23 @@
 
 
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
-			      struct rx_action *action)
+			      const struct ieee80211_mgmt *mgmt, size_t len)
 {
 	const u8 *pos, *end;
 	u8 act;
 
-	if (action->data == NULL || action->len == 0)
+	if (len < IEEE80211_HDRLEN + 2)
 		return;
 
-	pos = action->data;
-	end = pos + action->len;
+	pos = &mgmt->u.action.category;
+	pos++;
 	act = *pos++;
+	end = ((const u8 *) mgmt) + len;
 
 	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
-		   act, MAC2STR(action->sa));
+		   act, MAC2STR(mgmt->sa));
 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
-	    os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+	    os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
 			   "frame");
 		return;
@@ -756,10 +777,10 @@
 	switch (act) {
 	case WNM_BSS_TRANS_MGMT_REQ:
 		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
-						 !(action->da[0] & 0x01));
+						 !(mgmt->da[0] & 0x01));
 		break;
 	case WNM_SLEEP_MODE_RESP:
-		ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
+		ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
 		break;
 	default:
 		wpa_printf(MSG_ERROR, "WNM: Unknown request");
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 2933926..de87301 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -9,9 +9,6 @@
 #ifndef WNM_STA_H
 #define WNM_STA_H
 
-struct rx_action;
-struct wpa_supplicant;
-
 struct tsf_info {
 	u8 present;
 	u8 tsf_offset[2];
@@ -78,7 +75,7 @@
 				 u8 action, u16 intval, struct wpabuf *tfs_req);
 
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
-			      struct rx_action *action);
+			      const struct ieee80211_mgmt *mgmt, size_t len);
 
 void wnm_scan_response(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a379d65..6278806 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -28,7 +28,7 @@
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -496,6 +496,8 @@
 		return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
 	if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
 		return wpa_ctrl_command(ctrl, "STATUS-WPS");
+	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
 	return wpa_ctrl_command(ctrl, "STATUS");
 }
 
@@ -613,7 +615,9 @@
 		"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",
@@ -623,9 +627,10 @@
 		"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"
+		"ignore_old_scan_res", "freq_list", "external_sim",
+		"tdls_external_control"
 	};
-	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+	int i, num_fields = ARRAY_SIZE(fields);
 
 	if (arg == 1) {
 		char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -831,32 +836,6 @@
 }
 
 
-static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
-					   char *argv[])
-{
-	int ret;
-	char *buf;
-	size_t buflen;
-
-	if (argc != 1) {
-		printf("Invalid 'nfc_rx_handover_req' command - one argument "
-		       "is required.\n");
-		return -1;
-	}
-
-	buflen = 21 + os_strlen(argv[0]);
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return -1;
-	os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
-
-	ret = wpa_ctrl_command(ctrl, buf);
-	os_free(buf);
-
-	return ret;
-}
-
-
 static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
 					   char *argv[])
 {
@@ -1268,6 +1247,38 @@
 }
 
 
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid SIM command: needs two arguments "
+		       "(network id and SIM operation response)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long SIM command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long SIM command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
 				  char *argv[])
 {
@@ -1687,6 +1698,13 @@
 {
 	return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
 }
+
+static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
+}
+
 #endif /* CONFIG_AP */
 
 
@@ -2078,7 +2096,7 @@
 		"disc_int",
 		"per_sta_psk",
 	};
-	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+	int i, num_fields = ARRAY_SIZE(fields);
 
 	if (arg == 1) {
 		char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -2372,23 +2390,9 @@
 #ifdef ANDROID
 static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	char cmd[256];
-	int i;
-	int len;
-
-	if (argc < 1) {
-		printf("Invalid DRIVER command: needs one argument (cmd)\n");
-		return -1;
-	}
-
-	len = os_snprintf(cmd, sizeof(cmd), "DRIVER %s", argv[0]);
-	for (i=1; i < argc; i++)
-		len += os_snprintf(cmd + len, sizeof(cmd) - len, " %s", argv[i]);
-	cmd[sizeof(cmd) - 1] = '\0';
-	printf("%s: %s\n", __func__, cmd);
-	return wpa_ctrl_command(ctrl, cmd);
+	return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
 }
-#endif
+#endif /* ANDROID */
 
 
 static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -2397,6 +2401,12 @@
 }
 
 
+static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv);
+}
+
+
 enum wpa_cli_cmd_flags {
 	cli_cmd_flag_none		= 0x00,
 	cli_cmd_flag_sensitive		= 0x01
@@ -2486,6 +2496,9 @@
 	  cli_cmd_flag_sensitive,
 	  "<network id> <passphrase> = configure private key passphrase\n"
 	  "  for an SSID" },
+	{ "sim", wpa_cli_cmd_sim, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <pin> = report SIM operation result" },
 	{ "bssid", wpa_cli_cmd_bssid, NULL,
 	  cli_cmd_flag_none,
 	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
@@ -2628,9 +2641,6 @@
 	{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
 	  cli_cmd_flag_none,
 	  "<NDEF> <WPS> = create NFC handover select" },
-	{ "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
-	  cli_cmd_flag_none,
-	  "<hexdump of payload> = report received NFC handover request" },
 	{ "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
 	  cli_cmd_flag_none,
 	  "<hexdump of payload> = report received NFC handover select" },
@@ -2687,6 +2697,11 @@
 	{ "disassociate", wpa_cli_cmd_disassociate, NULL,
 	  cli_cmd_flag_none,
 	  "<addr> = disassociate a station" },
+	{ "chan_switch", wpa_cli_cmd_chanswitch, NULL,
+	  cli_cmd_flag_none,
+	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
+	  " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
+	  " = CSA parameters" },
 #endif /* CONFIG_AP */
 	{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
 	  "= notification of suspend/hibernate" },
@@ -2853,10 +2868,11 @@
 	{ "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
 	  "= flush wpa_supplicant state" },
 #ifdef ANDROID
-	{ "driver", wpa_cli_cmd_driver, NULL,
-	  cli_cmd_flag_none,
+	{ "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
 	  "<command> = driver private commands" },
-#endif
+#endif /* ANDROID */
+	{ "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
+	  "= radio_work <show/add/done>" },
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -2917,7 +2933,7 @@
 	int i, count;
 	struct cli_txt_entry *e;
 
-	count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+	count = ARRAY_SIZE(wpa_cli_commands);
 	count += dl_list_len(&p2p_groups);
 	count += dl_list_len(&ifnames);
 	res = os_calloc(count + 1, sizeof(char *));
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 4afaae9..5426177 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -552,8 +552,6 @@
 }
 
 
-extern struct wpa_driver_ops *wpa_drivers[];
-
 static struct wpa_priv_interface *
 wpa_priv_interface_init(const char *dir, const char *params)
 {
@@ -946,8 +944,6 @@
 }
 
 
-extern int wpa_debug_level;
-
 int main(int argc, char *argv[])
 {
 	int c, i;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index b431662..e942b62 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -54,7 +54,7 @@
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2014, 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"
@@ -104,11 +104,6 @@
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-extern struct wpa_driver_ops *wpa_drivers[];
-
 /* Configure default/group WEP keys for static WEP */
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
@@ -200,8 +195,6 @@
 	 * So, wait a second until scanning again.
 	 */
 	wpa_supplicant_req_scan(wpa_s, 1, 0);
-
-	wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -217,7 +210,7 @@
 void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
 				     int sec, int usec)
 {
-	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+	if (wpa_s->conf->ap_scan == 0 &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
 		return;
 
@@ -293,16 +286,16 @@
 				EAPOL_REQUIRE_KEY_BROADCAST;
 		}
 
-		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
 			eapol_conf.required_keys = 0;
 	}
-	if (wpa_s->conf)
-		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
 	eapol_conf.eap_disabled =
 		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+	eapol_conf.external_sim = wpa_s->conf->external_sim;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 }
@@ -459,6 +452,9 @@
 	os_free(wpa_s->next_scan_freqs);
 	wpa_s->next_scan_freqs = NULL;
 
+	os_free(wpa_s->manual_scan_freqs);
+	wpa_s->manual_scan_freqs = NULL;
+
 	gas_query_deinit(wpa_s->gas);
 	wpa_s->gas = NULL;
 
@@ -481,6 +477,9 @@
 	wpa_s->ext_pw = NULL;
 
 	wpabuf_free(wpa_s->last_gas_resp);
+	wpa_s->last_gas_resp = NULL;
+	wpabuf_free(wpa_s->prev_gas_resp);
+	wpa_s->prev_gas_resp = NULL;
 
 	os_free(wpa_s->last_scan_res);
 	wpa_s->last_scan_res = NULL;
@@ -497,29 +496,23 @@
  */
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
-	if (wpa_s->keys_cleared) {
-		/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
-		 * timing issues with keys being cleared just before new keys
-		 * are set or just after association or something similar. This
-		 * shows up in group key handshake failing often because of the
-		 * client not receiving the first encrypted packets correctly.
-		 * Skipping some of the extra key clearing steps seems to help
-		 * in completing group key handshake more reliably. */
-		wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
-			"skip key clearing");
-		return;
-	}
+	int i, max;
+
+#ifdef CONFIG_IEEE80211W
+	max = 6;
+#else /* CONFIG_IEEE80211W */
+	max = 4;
+#endif /* CONFIG_IEEE80211W */
 
 	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
-	if (addr) {
+	for (i = 0; i < max; i++) {
+		if (wpa_s->keys_cleared & BIT(i))
+			continue;
+		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+				NULL, 0);
+	}
+	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+	    !is_zero_ether_addr(addr)) {
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
 				0);
 		/* MLME-SETPROTECTION.request(None) */
@@ -528,7 +521,7 @@
 			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
 			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
 	}
-	wpa_s->keys_cleared = 1;
+	wpa_s->keys_cleared = (u32) -1;
 }
 
 
@@ -570,14 +563,22 @@
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+	const char *name;
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
+		name = wpa_s->current_ssid->bgscan;
+	else
+		name = wpa_s->conf->bgscan;
+	if (name == NULL)
+		return;
 	if (wpas_driver_bss_selection(wpa_s))
 		return;
 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
 		return;
 
 	bgscan_deinit(wpa_s);
-	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
-		if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+	if (wpa_s->current_ssid) {
+		if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
 				"bgscan");
 			/*
@@ -651,11 +652,13 @@
 		wpa_supplicant_state_txt(wpa_s->wpa_state),
 		wpa_supplicant_state_txt(state));
 
-#ifdef ANDROID_P2P
-	if(state == WPA_ASSOCIATED && wpa_s->current_ssid) {
-		wpa_s->current_ssid->assoc_retry = 0;
+	if (state == WPA_INTERFACE_DISABLED) {
+		/* Assure normal scan when interface is restored */
+		wpa_s->normal_scans = 0;
 	}
-#endif /* ANDROID_P2P */
+
+	if (state == WPA_COMPLETED)
+		wpas_connect_work_done(wpa_s);
 
 	if (state != WPA_SCANNING)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
@@ -664,7 +667,7 @@
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
-			MACSTR " completed (auth) [id=%d id_str=%s]",
+			MACSTR " completed [id=%d id_str=%s]",
 			MAC2STR(wpa_s->bssid),
 			ssid ? ssid->id : -1,
 			ssid && ssid->id_str ? ssid->id_str : "");
@@ -677,6 +680,7 @@
 		wpa_drv_set_supp_port(wpa_s, 1);
 #endif /* IEEE8021X_EAPOL */
 		wpa_s->after_wps = 0;
+		wpa_s->known_wps_freq = 0;
 #ifdef CONFIG_P2P
 		wpas_p2p_completed(wpa_s);
 #endif /* CONFIG_P2P */
@@ -696,7 +700,7 @@
 #ifdef CONFIG_BGSCAN
 	if (state == WPA_COMPLETED)
 		wpa_supplicant_start_bgscan(wpa_s);
-	else
+	else if (state < WPA_ASSOCIATED)
 		wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
 
@@ -722,9 +726,15 @@
 #ifdef CONFIG_WPS
 	struct wpa_supplicant *wpa_s = global->ifaces;
 	while (wpa_s) {
+		struct wpa_supplicant *next = wpa_s->next;
+#ifdef CONFIG_P2P
+		if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
+		    (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
+			wpas_p2p_disconnect(wpa_s);
+#endif /* CONFIG_P2P */
 		if (wpas_wps_terminate_pending(wpa_s) == 1)
 			pending = 1;
-		wpa_s = wpa_s->next;
+		wpa_s = next;
 	}
 #endif /* CONFIG_WPS */
 	if (pending)
@@ -853,34 +863,6 @@
 }
 
 
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
-{
-	switch (key_mgmt) {
-	case WPA_KEY_MGMT_NONE:
-		return KEY_MGMT_NONE;
-	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
-		return KEY_MGMT_802_1X_NO_WPA;
-	case WPA_KEY_MGMT_IEEE8021X:
-		return KEY_MGMT_802_1X;
-	case WPA_KEY_MGMT_WPA_NONE:
-		return KEY_MGMT_WPA_NONE;
-	case WPA_KEY_MGMT_FT_IEEE8021X:
-		return KEY_MGMT_FT_802_1X;
-	case WPA_KEY_MGMT_FT_PSK:
-		return KEY_MGMT_FT_PSK;
-	case WPA_KEY_MGMT_IEEE8021X_SHA256:
-		return KEY_MGMT_802_1X_SHA256;
-	case WPA_KEY_MGMT_PSK_SHA256:
-		return KEY_MGMT_PSK_SHA256;
-	case WPA_KEY_MGMT_WPS:
-		return KEY_MGMT_WPS;
-	case WPA_KEY_MGMT_PSK:
-	default:
-		return KEY_MGMT_PSK;
-	}
-}
-
-
 static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
 					 struct wpa_ssid *ssid,
 					 struct wpa_ie_data *ie)
@@ -1220,6 +1202,10 @@
 #endif /* CONFIG_INTERWORKING */
 		break;
 	case 4: /* Bits 32-39 */
+#ifdef CONFIG_INTERWORKING
+		if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+			*pos |= 0x01; /* Bit 32 - QoS Map */
+#endif /* CONFIG_INTERWORKING */
 		break;
 	case 5: /* Bits 40-47 */
 		break;
@@ -1259,6 +1245,70 @@
 }
 
 
+static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
+			  struct wpa_bss *test_bss)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (bss == test_bss)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
+			   struct wpa_ssid *test_ssid)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid == test_ssid)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+			struct wpa_ssid *test_ssid)
+{
+	if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
+		return 0;
+
+	return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
+}
+
+
+void wpas_connect_work_free(struct wpa_connect_work *cwork)
+{
+	if (cwork == NULL)
+		return;
+	os_free(cwork);
+}
+
+
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_connect_work *cwork;
+	struct wpa_radio_work *work = wpa_s->connect_work;
+
+	if (!work)
+		return;
+
+	wpa_s->connect_work = NULL;
+	cwork = work->ctx;
+	work->ctx = NULL;
+	wpas_connect_work_free(cwork);
+	radio_work_done(work);
+}
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
+
 /**
  * wpa_supplicant_associate - Request association
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1270,29 +1320,12 @@
 void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 			      struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
-	u8 wpa_ie[200];
-	size_t wpa_ie_len;
-	int use_crypt, ret, i, bssid_changed;
-	int algs = WPA_AUTH_ALG_OPEN;
-	enum wpa_cipher cipher_pairwise, cipher_group;
-	struct wpa_driver_associate_params params;
-	int wep_keys_set = 0;
-	int assoc_failed = 0;
-	struct wpa_ssid *old_ssid;
-	u8 ext_capab[10];
-	int ext_capab_len;
-#ifdef CONFIG_HT_OVERRIDES
-	struct ieee80211_ht_capabilities htcaps;
-	struct ieee80211_ht_capabilities htcaps_mask;
-#endif /* CONFIG_HT_OVERRIDES */
+	struct wpa_connect_work *cwork;
 
 #ifdef CONFIG_IBSS_RSN
 	ibss_rsn_deinit(wpa_s->ibss_rsn);
 	wpa_s->ibss_rsn = NULL;
 #endif /* CONFIG_IBSS_RSN */
-#ifdef ANDROID_P2P
-	int freq = 0;
-#endif
 
 	if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
 	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -1328,8 +1361,68 @@
 		return;
 	}
 
+	if (wpa_s->connect_work) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
+		return;
+	}
+
+	cwork = os_zalloc(sizeof(*cwork));
+	if (cwork == NULL)
+		return;
+
+	cwork->bss = bss;
+	cwork->ssid = ssid;
+
+	if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
+			   wpas_start_assoc_cb, cwork) < 0) {
+		os_free(cwork);
+	}
+}
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+{
+	struct wpa_connect_work *cwork = work->ctx;
+	struct wpa_bss *bss = cwork->bss;
+	struct wpa_ssid *ssid = cwork->ssid;
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	u8 wpa_ie[200];
+	size_t wpa_ie_len;
+	int use_crypt, ret, i, bssid_changed;
+	int algs = WPA_AUTH_ALG_OPEN;
+	unsigned int cipher_pairwise, cipher_group;
+	struct wpa_driver_associate_params params;
+	int wep_keys_set = 0;
+	int assoc_failed = 0;
+	struct wpa_ssid *old_ssid;
+#ifdef CONFIG_HT_OVERRIDES
+	struct ieee80211_ht_capabilities htcaps;
+	struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+
+	if (deinit) {
+		if (work->started) {
+			wpa_s->connect_work = NULL;
+
+			/* cancel possible auth. timeout */
+			eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
+					     NULL);
+		}
+		wpas_connect_work_free(cwork);
+		return;
+	}
+
+	wpa_s->connect_work = work;
+
+	if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
+		wpas_connect_work_done(wpa_s);
+		return;
+	}
+
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
+	wpa_s->eap_expected_failure = 0;
 	if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
 		const u8 *ie, *md = NULL;
@@ -1479,6 +1572,8 @@
 				"disallows" : "allows");
 		}
 	}
+
+	os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_HS20
@@ -1495,21 +1590,33 @@
 	}
 #endif /* CONFIG_HS20 */
 
-	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
-	if (ext_capab_len > 0) {
-		u8 *pos = wpa_ie;
-		if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
-			pos += 2 + pos[1];
-		os_memmove(pos + ext_capab_len, pos,
-			   wpa_ie_len - (pos - wpa_ie));
-		wpa_ie_len += ext_capab_len;
-		os_memcpy(pos, ext_capab, ext_capab_len);
+	/*
+	 * Workaround: Add Extended Capabilities element only if the AP
+	 * included this element in Beacon/Probe Response frames. Some older
+	 * APs seem to have interoperability issues if this element is
+	 * included, so while the standard may require us to include the
+	 * element in all cases, it is justifiable to skip it to avoid
+	 * interoperability issues.
+	 */
+	if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+		u8 ext_capab[10];
+		int ext_capab_len;
+		ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+		if (ext_capab_len > 0) {
+			u8 *pos = wpa_ie;
+			if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+				pos += 2 + pos[1];
+			os_memmove(pos + ext_capab_len, pos,
+				   wpa_ie_len - (pos - wpa_ie));
+			wpa_ie_len += ext_capab_len;
+			os_memcpy(pos, ext_capab, ext_capab_len);
+		}
 	}
 
 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
 	use_crypt = 1;
-	cipher_pairwise = wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
-	cipher_group = wpa_cipher_to_suite_driver(wpa_s->group_cipher);
+	cipher_pairwise = wpa_s->pairwise_cipher;
+	cipher_group = wpa_s->group_cipher;
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
 		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -1533,7 +1640,7 @@
 			/* Assume that dynamic WEP-104 keys will be used and
 			 * set cipher suites in order for drivers to expect
 			 * encryption. */
-			cipher_pairwise = cipher_group = CIPHER_WEP104;
+			cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
 		}
 	}
 #endif /* IEEE8021X_EAPOL */
@@ -1556,6 +1663,8 @@
 			params.bssid = bss->bssid;
 			params.freq = bss->freq;
 		}
+		params.bssid_hint = bss->bssid;
+		params.freq_hint = bss->freq;
 	} else {
 		params.ssid = ssid->ssid;
 		params.ssid_len = ssid->ssid_len;
@@ -1574,7 +1683,7 @@
 	params.wpa_ie_len = wpa_ie_len;
 	params.pairwise_suite = cipher_pairwise;
 	params.group_suite = cipher_group;
-	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+	params.key_mgmt_suite = wpa_s->key_mgmt;
 	params.wpa_proto = wpa_s->wpa_proto;
 	params.auth_alg = algs;
 	params.mode = ssid->mode;
@@ -1587,8 +1696,8 @@
 	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 
 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
-	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
-	     params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
+	    (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+	     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
 		params.passphrase = ssid->passphrase;
 		if (ssid->psk_set)
 			params.psk = ssid->psk;
@@ -1629,18 +1738,25 @@
 	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_HT_OVERRIDES */
 
-#ifdef ANDROID_P2P
-	/* If multichannel concurrency is not supported, check for any frequency
-	 * conflict and take appropriate action.
+#ifdef CONFIG_P2P
+	/*
+	 * If multi-channel concurrency is not supported, check for any
+	 * frequency conflict. In case of any frequency conflict, remove the
+	 * least prioritized connection.
 	 */
-	if ((wpa_s->num_multichan_concurrent < 2) &&
-		((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
-		wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
-																, freq, params.freq);
-		if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0) 
-			return;
+	if (wpa_s->num_multichan_concurrent < 2) {
+		int freq = wpa_drv_shared_freq(wpa_s);
+		if (freq > 0 && freq != params.freq) {
+			wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)",
+				   freq, params.freq);
+			if (wpas_p2p_handle_frequency_conflicts(wpa_s,
+								params.freq,
+								ssid) < 0)
+				return;
+		}
 	}
-#endif
+#endif /* CONFIG_P2P */
+
 	ret = wpa_drv_associate(wpa_s, &params);
 	if (ret < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -1952,6 +2068,59 @@
 
 
 /**
+ * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @pkcs11_engine_path: PKCS #11 engine path or NULL
+ * @pkcs11_module_path: PKCS #11 module path or NULL
+ * Returns: 0 on success; -1 on failure
+ *
+ * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
+ * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
+ * module path fails the paths will be reset to the default value (NULL).
+ */
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+					   const char *pkcs11_engine_path,
+					   const char *pkcs11_module_path)
+{
+	char *pkcs11_engine_path_copy = NULL;
+	char *pkcs11_module_path_copy = NULL;
+
+	if (pkcs11_engine_path != NULL) {
+		pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
+		if (pkcs11_engine_path_copy == NULL)
+			return -1;
+	}
+	if (pkcs11_module_path != NULL) {
+		pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
+		if (pkcs11_module_path_copy == NULL) {
+			os_free(pkcs11_engine_path_copy);
+			return -1;
+		}
+	}
+
+	os_free(wpa_s->conf->pkcs11_engine_path);
+	os_free(wpa_s->conf->pkcs11_module_path);
+	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
+	wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
+
+	wpa_sm_set_eapol(wpa_s->wpa, NULL);
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_s->eapol = NULL;
+	if (wpa_supplicant_init_eapol(wpa_s)) {
+		/* Error -> Reset paths to the default value (NULL) once. */
+		if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
+			wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
+							       NULL);
+
+		return -1;
+	}
+	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+	return 0;
+}
+
+
+/**
  * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ap_scan: AP scan mode
@@ -2245,6 +2414,16 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
+#ifdef CONFIG_PEERKEY
+	if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
+	    wpa_s->current_ssid->peerkey &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+	    wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
+		return;
+	}
+#endif /* CONFIG_PEERKEY */
+
 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
 	    (wpa_s->last_eapol_matches_bssid &&
 #ifdef CONFIG_AP
@@ -2270,7 +2449,7 @@
 		wpabuf_free(wpa_s->pending_eapol_rx);
 		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
 		if (wpa_s->pending_eapol_rx) {
-			os_get_time(&wpa_s->pending_eapol_rx_time);
+			os_get_reltime(&wpa_s->pending_eapol_rx_time);
 			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
 				  ETH_ALEN);
 		}
@@ -2455,6 +2634,10 @@
 	wpa_s->prev_scan_wildcard = 0;
 
 	if (wpa_supplicant_enabled_networks(wpa_s)) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			interface_count = 0;
+		}
 		if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
 						      100000))
 			wpa_supplicant_req_scan(wpa_s, interface_count,
@@ -2747,7 +2930,7 @@
 	if (!wpa_s->conf->pcsc_reader)
 		return 0;
 
-	wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+	wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
 	if (!wpa_s->scard)
 		return 1;
 
@@ -2813,10 +2996,302 @@
 }
 
 
+static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
+					      const char *rn)
+{
+	struct wpa_supplicant *iface = wpa_s->global->ifaces;
+	struct wpa_radio *radio;
+
+	while (rn && iface) {
+		radio = iface->radio;
+		if (radio && os_strcmp(rn, radio->name) == 0) {
+			wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
+				   wpa_s->ifname, rn);
+			dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+			return radio;
+		}
+
+		iface = iface->next;
+	}
+
+	wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
+		   wpa_s->ifname, rn ? rn : "N/A");
+	radio = os_zalloc(sizeof(*radio));
+	if (radio == NULL)
+		return NULL;
+
+	if (rn)
+		os_strlcpy(radio->name, rn, sizeof(radio->name));
+	dl_list_init(&radio->ifaces);
+	dl_list_init(&radio->work);
+	dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+
+	return radio;
+}
+
+
+static void radio_work_free(struct wpa_radio_work *work)
+{
+	if (work->wpa_s->scan_work == work) {
+		/* This should not really happen. */
+		wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
+			work->type, work, work->started);
+		work->wpa_s->scan_work = NULL;
+	}
+
+#ifdef CONFIG_P2P
+	if (work->wpa_s->p2p_scan_work == work) {
+		/* This should not really happen. */
+		wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
+			work->type, work, work->started);
+		work->wpa_s->p2p_scan_work = NULL;
+	}
+#endif /* CONFIG_P2P */
+
+	dl_list_del(&work->list);
+	os_free(work);
+}
+
+
+static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_radio *radio = eloop_ctx;
+	struct wpa_radio_work *work;
+	struct os_reltime now, diff;
+	struct wpa_supplicant *wpa_s;
+
+	work = dl_list_first(&radio->work, struct wpa_radio_work, list);
+	if (work == NULL)
+		return;
+
+	if (work->started)
+		return; /* already started and still in progress */
+
+	wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
+			      radio_list);
+	if (wpa_s && wpa_s->external_scan_running) {
+		wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
+		return;
+	}
+
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &work->time, &diff);
+	wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait",
+		work->type, work, diff.sec, diff.usec);
+	work->started = 1;
+	work->time = now;
+	work->cb(work, 0);
+}
+
+
+/*
+ * This function removes both started and pending radio works running on
+ * the provided interface's radio.
+ * Prior to the removal of the radio work, its callback (cb) is called with
+ * deinit set to be 1. Each work's callback is responsible for clearing its
+ * internal data and restoring to a correct state.
+ * @wpa_s: wpa_supplicant data
+ * @type: type of works to be removed
+ * @remove_all: 1 to remove all the works on this radio, 0 to remove only
+ * this interface's works.
+ */
+void radio_remove_works(struct wpa_supplicant *wpa_s,
+			const char *type, int remove_all)
+{
+	struct wpa_radio_work *work, *tmp;
+	struct wpa_radio *radio = wpa_s->radio;
+
+	dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
+			      list) {
+		if (type && os_strcmp(type, work->type) != 0)
+			continue;
+
+		/* skip other ifaces' works */
+		if (!remove_all && work->wpa_s != wpa_s)
+			continue;
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
+			work->type, work, work->started ? " (started)" : "");
+		work->cb(work, 1);
+		radio_work_free(work);
+	}
+
+	/* in case we removed the started work */
+	radio_work_check_next(wpa_s);
+}
+
+
+static void radio_remove_interface(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_radio *radio = wpa_s->radio;
+
+	if (!radio)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
+		   wpa_s->ifname, radio->name);
+	dl_list_del(&wpa_s->radio_list);
+	if (!dl_list_empty(&radio->ifaces)) {
+		wpa_s->radio = NULL;
+		return; /* Interfaces remain for this radio */
+	}
+
+	wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
+	radio_remove_works(wpa_s, NULL, 0);
+	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+	wpa_s->radio = NULL;
+	os_free(radio);
+}
+
+
+void radio_work_check_next(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_radio *radio = wpa_s->radio;
+
+	if (dl_list_empty(&radio->work))
+		return;
+	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+	eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
+}
+
+
+/**
+ * radio_add_work - Add a radio work item
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency of the offchannel operation in MHz or 0
+ * @type: Unique identifier for each type of work
+ * @next: Force as the next work to be executed
+ * @cb: Callback function for indicating when radio is available
+ * @ctx: Context pointer for the work (work->ctx in cb())
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to request time for an operation that requires
+ * exclusive radio control. Once the radio is available, the registered callback
+ * function will be called. radio_work_done() must be called once the exclusive
+ * radio operation has been completed, so that the radio is freed for other
+ * operations. The special case of deinit=1 is used to free the context data
+ * during interface removal. That does not allow the callback function to start
+ * the radio operation, i.e., it must free any resources allocated for the radio
+ * work and return.
+ *
+ * The @freq parameter can be used to indicate a single channel on which the
+ * offchannel operation will occur. This may allow multiple radio work
+ * operations to be performed in parallel if they apply for the same channel.
+ * Setting this to 0 indicates that the work item may use multiple channels or
+ * requires exclusive control of the radio.
+ */
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+		   const char *type, int next,
+		   void (*cb)(struct wpa_radio_work *work, int deinit),
+		   void *ctx)
+{
+	struct wpa_radio_work *work;
+	int was_empty;
+
+	work = os_zalloc(sizeof(*work));
+	if (work == NULL)
+		return -1;
+	wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
+	os_get_reltime(&work->time);
+	work->freq = freq;
+	work->type = type;
+	work->wpa_s = wpa_s;
+	work->cb = cb;
+	work->ctx = ctx;
+
+	was_empty = dl_list_empty(&wpa_s->radio->work);
+	if (next)
+		dl_list_add(&wpa_s->radio->work, &work->list);
+	else
+		dl_list_add_tail(&wpa_s->radio->work, &work->list);
+	if (was_empty) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
+		radio_work_check_next(wpa_s);
+	}
+
+	return 0;
+}
+
+
+/**
+ * radio_work_done - Indicate that a radio work item has been completed
+ * @work: Completed work
+ *
+ * This function is called once the callback function registered with
+ * radio_add_work() has completed its work.
+ */
+void radio_work_done(struct wpa_radio_work *work)
+{
+	struct wpa_supplicant *wpa_s = work->wpa_s;
+	struct os_reltime now, diff;
+	unsigned int started = work->started;
+
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &work->time, &diff);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
+		work->type, work, started ? "done" : "canceled",
+		diff.sec, diff.usec);
+	radio_work_free(work);
+	if (started)
+		radio_work_check_next(wpa_s);
+}
+
+
+static int wpas_init_driver(struct wpa_supplicant *wpa_s,
+			    struct wpa_interface *iface)
+{
+	const char *ifname, *driver, *rn;
+
+	driver = iface->driver;
+next_driver:
+	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+		return -1;
+
+	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
+	if (wpa_s->drv_priv == NULL) {
+		const char *pos;
+		pos = driver ? os_strchr(driver, ',') : NULL;
+		if (pos) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+				"driver interface - try next driver wrapper");
+			driver = pos + 1;
+			goto next_driver;
+		}
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+			"interface");
+		return -1;
+	}
+	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+			"driver_param '%s'", wpa_s->conf->driver_param);
+		return -1;
+	}
+
+	ifname = wpa_drv_get_ifname(wpa_s);
+	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+			"interface name with '%s'", ifname);
+		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+	}
+
+	if (wpa_s->driver->get_radio_name)
+		rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	else
+		rn = NULL;
+	if (rn && rn[0] == '\0')
+		rn = NULL;
+
+	wpa_s->radio = radio_add_interface(wpa_s, rn);
+	if (wpa_s->radio == NULL)
+		return -1;
+
+	return 0;
+}
+
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 				     struct wpa_interface *iface)
 {
-	const char *ifname, *driver;
 	struct wpa_driver_capa capa;
 
 	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
@@ -2908,38 +3383,9 @@
 	 * L2 receive handler so that association events are processed before
 	 * EAPOL-Key packets if both become available for the same select()
 	 * call. */
-	driver = iface->driver;
-next_driver:
-	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+	if (wpas_init_driver(wpa_s, iface) < 0)
 		return -1;
 
-	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
-	if (wpa_s->drv_priv == NULL) {
-		const char *pos;
-		pos = driver ? os_strchr(driver, ',') : NULL;
-		if (pos) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
-				"driver interface - try next driver wrapper");
-			driver = pos + 1;
-			goto next_driver;
-		}
-		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
-			"interface");
-		return -1;
-	}
-	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
-		wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
-			"driver_param '%s'", wpa_s->conf->driver_param);
-		return -1;
-	}
-
-	ifname = wpa_drv_get_ifname(wpa_s);
-	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
-			"interface name with '%s'", ifname);
-		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
-	}
-
 	if (wpa_supplicant_init_wpa(wpa_s) < 0)
 		return -1;
 
@@ -3066,7 +3512,8 @@
 #ifdef CONFIG_EAP_PROXY
 {
 	size_t len;
-	wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &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)",
@@ -3109,6 +3556,9 @@
 	}
 #endif /* CONFIG_P2P */
 
+	wpas_ctrl_radio_work_flush(wpa_s);
+	radio_remove_interface(wpa_s);
+
 	if (wpa_s->drv_priv)
 		wpa_drv_deinit(wpa_s);
 
@@ -3502,7 +3952,8 @@
 	os_free(global->params.override_driver);
 	os_free(global->params.override_ctrl_interface);
 
-	os_free(global->p2p_disallow_freq);
+	os_free(global->p2p_disallow_freq.range);
+	os_free(global->p2p_go_avoid_freq.range);
 	os_free(global->add_psk);
 
 	os_free(global);
@@ -3595,6 +4046,8 @@
 	int count;
 	int *freqs = NULL;
 
+	wpas_connect_work_done(wpa_s);
+
 	/*
 	 * Remove possible authentication timeout since the connection failed.
 	 */
@@ -3681,8 +4134,6 @@
 	 */
 	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
 				1000 * (timeout % 1000));
-
-	wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -3753,6 +4204,10 @@
 		if (ssid == wpa_s->current_ssid)
 			wpa_s->reassociate = 1;
 		break;
+	case WPA_CTRL_REQ_SIM:
+		os_free(eap->external_sim_resp);
+		eap->external_sim_resp = os_strdup(value);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
 		return -1;
@@ -3818,7 +4273,7 @@
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	int dur;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (ssid == NULL) {
 		wpa_printf(MSG_DEBUG, "Authentication failure but no known "
@@ -3855,7 +4310,7 @@
 	else
 		dur = 10;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 	if (now.sec + dur <= ssid->disabled_until.sec)
 		return;
 
@@ -3943,42 +4398,15 @@
 }
 
 
-/**
- * wpas_wpa_is_in_progress - Check whether a connection is in progress
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * This function is to check if the wpa state is in beginning of the connection
- * during 4-way handshake or group key handshake with WPA on any shared
- * interface.
- */
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len)
 {
-	const char *rn, *rn2;
-	struct wpa_supplicant *ifs;
+	unsigned int i;
 
-	if (!wpa_s->driver->get_radio_name)
-                return 0;
-
-	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
-		return 0;
-
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
-			continue;
-
-		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
-		if (!rn2 || os_strcmp(rn, rn2) != 0)
-			continue;
-		if (ifs->wpa_state >= WPA_AUTHENTICATING &&
-		    ifs->wpa_state != WPA_COMPLETED) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
-				"on interface %s - defer scan", ifs->ifname);
-			return 1;
-		}
-	}
-
-	return 0;
+	wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
+		len, title);
+	for (i = 0; i < len; i++)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
 }
 
 
@@ -3989,12 +4417,13 @@
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len)
 {
-	const char *rn, *rn2;
 	struct wpa_supplicant *ifs;
 	u8 bssid[ETH_ALEN];
 	int freq;
 	unsigned int idx = 0, i;
 
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Determining shared radio frequencies (max len %u)", len);
 	os_memset(freq_array, 0, sizeof(int) * len);
 
 	/* First add the frequency of the local interface */
@@ -4012,20 +4441,13 @@
 		if (freq > 0 && idx < len &&
 		    (idx == 0 || freq_array[0] != freq))
 			freq_array[idx++] = freq;
+		dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
 		return idx;
 	}
 
-	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
-		return idx;
-
-	for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len;
-	     ifs = ifs->next) {
-		if (wpa_s == ifs || !ifs->driver->get_radio_name)
-			continue;
-
-		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
-		if (!rn2 || os_strcmp(rn, rn2) != 0)
+	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+			 radio_list) {
+		if (wpa_s == ifs)
 			continue;
 
 		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
@@ -4047,5 +4469,7 @@
 		if (i == idx)
 			freq_array[idx++] = freq;
 	}
+
+	dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
 	return idx;
 }
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d73d371..b627632 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -241,14 +241,14 @@
 # This is an optional set of parameters for automatic scanning
 # within an interface in following format:
 #autoscan=<autoscan module name>:<module parameters>
-# autoscan is like bgscan but on disconnected or inactive state.
-# For instance, on exponential module parameters would be <base>:<limit>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
 #autoscan=exponential:3:300
 # Which means a delay between scans on a base exponential of 3,
-# up to the limit of 300 seconds (3, 9, 27 ... 300)
-# For periodic module, parameters would be <fixed interval>
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
 #autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan
 
 # filter_ssids - SSID-based scan result filtering
 # 0 = do not filter scan results (default)
@@ -342,6 +342,8 @@
 #
 # credential fields:
 #
+# temporary: Whether this credential is temporary and not to be saved
+#
 # priority: Priority group
 #	By default, all networks and credentials get the same priority group
 #	(0). This field can be used to give higher priority for credentials
@@ -399,9 +401,11 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# domain: Home service provider FQDN
+# domain: Home service provider FQDN(s)
 #	This is used to compare against the Domain Name List to figure out
-#	whether the AP is operated by the Home SP.
+#	whether the AP is operated by the Home SP. Multiple domain entries can
+#	be used to configure alternative FQDNs that will be considered home
+#	networks.
 #
 # roaming_consortium: Roaming Consortium OI
 #	If roaming_consortium_len is non-zero, this field contains the
@@ -504,9 +508,10 @@
 # 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
 # 1 = IBSS (ad-hoc, peer-to-peer)
 # 2 = AP (access point)
-# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
-# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires
-# following network block options:
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and
+# WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key
+# TKIP/CCMP) is available for backwards compatibility, but its use is
+# deprecated. WPA-None requires following network block options:
 # proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
 # both), and psk must also be set.
 #
@@ -548,6 +553,10 @@
 # <long interval>[:<database file name>]"
 # bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
 #
+# This option can also be set outside of all network blocks for the bgscan
+# parameter to apply for all the networks that have no specific bgscan
+# parameter.
+#
 # proto: list of accepted protocols
 # WPA = WPA/IEEE 802.11i/D3.0
 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
@@ -791,6 +800,10 @@
 #	EAP workarounds are disabled with eap_workarounds=0.
 #	For EAP-FAST, this must be set to 0 (or left unconfigured for the
 #	default value to be used automatically).
+# tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers
+#	that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
+#	that have issues interoperating with updated TLS version)
 #
 # Following certificate/private key fields are used in inner Phase2
 # authentication when using EAP-TTLS or EAP-PEAP.
@@ -1157,7 +1170,19 @@
 }
 
 
-# IBSS/ad-hoc network with WPA-None/TKIP.
+# IBSS/ad-hoc network with RSN
+network={
+	ssid="ibss-rsn"
+	key_mgmt=WPA-PSK
+	proto=RSN
+	psk="12345678"
+	mode=1
+	frequency=2412
+	pairwise=CCMP
+	group=CCMP
+}
+
+# IBSS/ad-hoc network with WPA-None/TKIP (deprecated)
 network={
 	ssid="test adhoc"
 	mode=1
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d69cd61..bcdb4d0 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, 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/list.h"
 #include "common/defs.h"
 #include "common/sae.h"
+#include "wps/wps_defs.h"
 #include "config_ssid.h"
 
 extern const char *wpa_supplicant_version;
@@ -227,12 +228,6 @@
 	char *service;
 };
 
-struct wpa_freq_range {
-	unsigned int min;
-	unsigned int max;
-};
-
-
 /**
  * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
  *
@@ -252,20 +247,20 @@
 	struct wpa_supplicant *p2p_group_formation;
 	struct wpa_supplicant *p2p_invite_group;
 	u8 p2p_dev_addr[ETH_ALEN];
-	struct os_time p2p_go_wait_client;
+	struct os_reltime p2p_go_wait_client;
 	struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
 	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
 	int p2p_disabled;
 	int cross_connection;
-	struct wpa_freq_range *p2p_disallow_freq;
-	unsigned int num_p2p_disallow_freq;
+	struct wpa_freq_range_list p2p_disallow_freq;
+	struct wpa_freq_range_list p2p_go_avoid_freq;
 	enum wpa_conc_pref {
 		WPA_CONC_PREF_NOT_SET,
 		WPA_CONC_PREF_STA,
 		WPA_CONC_PREF_P2P
 	} conc_pref;
-	unsigned int p2p_cb_on_scan_complete:1;
 	unsigned int p2p_per_sta_psk:1;
+	unsigned int p2p_fail_on_wps_complete:1;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	int wifi_display;
@@ -278,6 +273,60 @@
 
 
 /**
+ * struct wpa_radio - Internal data for per-radio information
+ *
+ * This structure is used to share data about configured interfaces
+ * (struct wpa_supplicant) that share the same physical radio, e.g., to allow
+ * better coordination of offchannel operations.
+ */
+struct wpa_radio {
+	char name[16]; /* from driver_ops get_radio_name() or empty if not
+			* available */
+	struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
+	struct dl_list work; /* struct wpa_radio_work::list entries */
+};
+
+/**
+ * struct wpa_radio_work - Radio work item
+ */
+struct wpa_radio_work {
+	struct dl_list list;
+	unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */
+	const char *type;
+	struct wpa_supplicant *wpa_s;
+	void (*cb)(struct wpa_radio_work *work, int deinit);
+	void *ctx;
+	unsigned int started:1;
+	struct os_reltime time;
+};
+
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+		   const char *type, int next,
+		   void (*cb)(struct wpa_radio_work *work, int deinit),
+		   void *ctx);
+void radio_work_done(struct wpa_radio_work *work);
+void radio_remove_works(struct wpa_supplicant *wpa_s,
+			const char *type, int remove_all);
+void radio_work_check_next(struct wpa_supplicant *wpa_s);
+
+struct wpa_connect_work {
+	unsigned int sme:1;
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid;
+};
+
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+			struct wpa_ssid *test_ssid);
+void wpas_connect_work_free(struct wpa_connect_work *cwork);
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s);
+
+struct wpa_external_work {
+	unsigned int id;
+	char type[100];
+	unsigned int timeout;
+};
+
+/**
  * offchannel_send_action_result - Result of offchannel send Action frame
  */
 enum offchannel_send_action_result {
@@ -296,7 +345,7 @@
 		WPS_AP_SEL_REG_OUR
 	} type;
 	unsigned int tries;
-	struct os_time last_attempt;
+	struct os_reltime last_attempt;
 };
 
 struct wpa_ssid_value {
@@ -314,6 +363,8 @@
  */
 struct wpa_supplicant {
 	struct wpa_global *global;
+	struct wpa_radio *radio; /* shared radio context */
+	struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */
 	struct wpa_supplicant *parent;
 	struct wpa_supplicant *next;
 	struct l2_packet_data *l2;
@@ -336,7 +387,7 @@
 	char *confanother;
 	struct wpa_config *conf;
 	int countermeasures;
-	os_time_t last_michael_mic_error;
+	struct os_reltime last_michael_mic_error;
 	u8 bssid[ETH_ALEN];
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
@@ -400,8 +451,7 @@
 	struct wpa_bss **last_scan_res;
 	unsigned int last_scan_res_used;
 	unsigned int last_scan_res_size;
-	int last_scan_full;
-	struct os_time last_scan;
+	struct os_reltime last_scan;
 
 	struct wpa_driver_ops *driver;
 	int interface_removed; /* whether the network interface has been
@@ -412,6 +462,7 @@
 	struct ctrl_iface_priv *ctrl_iface;
 
 	enum wpa_states wpa_state;
+	struct wpa_radio_work *scan_work;
 	int scanning;
 	int sched_scanning;
 	int new_connection;
@@ -425,7 +476,8 @@
 
 	unsigned char last_eapol_src[ETH_ALEN];
 
-	int keys_cleared;
+	unsigned int keys_cleared; /* bitfield of key indexes that the driver is
+				    * known not to be configured with a key */
 
 	struct wpa_blacklist *blacklist;
 
@@ -470,10 +522,19 @@
 		 * to be run.
 		 */
 		MANUAL_SCAN_REQ
-	} scan_req;
-	struct os_time scan_trigger_time;
+	} scan_req, last_scan_req;
+	struct os_reltime scan_trigger_time, scan_start_time;
 	int scan_runs; /* number of scan runs since WPS was started */
 	int *next_scan_freqs;
+	int *manual_scan_freqs;
+	unsigned int manual_scan_passive:1;
+	unsigned int manual_scan_use_id:1;
+	unsigned int manual_scan_only_new:1;
+	unsigned int own_scan_requested:1;
+	unsigned int own_scan_running:1;
+	unsigned int external_scan_running:1;
+	unsigned int clear_driver_scan_cache:1;
+	unsigned int manual_scan_id;
 	int scan_interval; /* time in sec between scans to find suitable AP */
 	int normal_scans; /* normal scans run before sched_scan */
 	int scan_for_connection; /* whether the scan request was triggered for
@@ -509,9 +570,10 @@
 	int blacklist_cleared;
 
 	struct wpabuf *pending_eapol_rx;
-	struct os_time pending_eapol_rx_time;
+	struct os_reltime pending_eapol_rx_time;
 	u8 pending_eapol_rx_src[ETH_ALEN];
 	unsigned int last_eapol_matches_bssid:1;
+	unsigned int eap_expected_failure:1;
 
 	struct ibss_rsn *ibss_rsn;
 
@@ -543,7 +605,7 @@
 		u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
 					* sa_query_count octets of pending
 					* SA Query transaction identifiers */
-		struct os_time sa_query_start;
+		struct os_reltime sa_query_start;
 		u8 sched_obss_scan;
 		u16 obss_scan_int;
 		u16 bss_max_idle_period;
@@ -610,6 +672,8 @@
 	u8 pending_join_iface_addr[ETH_ALEN];
 	u8 pending_join_dev_addr[ETH_ALEN];
 	int pending_join_wps_method;
+	u8 p2p_join_ssid[32];
+	size_t p2p_join_ssid_len;
 	int p2p_join_scan_count;
 	int auto_pd_scan_retry;
 	int force_long_sd;
@@ -639,20 +703,35 @@
 	 */
 	char cross_connect_uplink[100];
 
-	unsigned int sta_scan_pending:1;
 	unsigned int p2p_auto_join:1;
 	unsigned int p2p_auto_pd:1;
 	unsigned int p2p_persistent_group:1;
 	unsigned int p2p_fallback_to_go_neg:1;
 	unsigned int p2p_pd_before_go_neg:1;
 	unsigned int p2p_go_ht40:1;
+	unsigned int p2p_go_vht:1;
 	unsigned int user_initiated_pd:1;
+	unsigned int p2p_go_group_formation_completed:1;
+	unsigned int waiting_presence_resp;
+	int p2p_first_connection_timeout;
+	unsigned int p2p_nfc_tag_enabled:1;
+	unsigned int p2p_peer_oob_pk_hash_known:1;
+	unsigned int p2p_disable_ip_addr_req:1;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
 	int p2p_connect_freq;
-	struct os_time p2p_auto_started;
+	struct os_reltime p2p_auto_started;
 	struct wpa_ssid *p2p_last_4way_hs_fail;
+	struct wpa_radio_work *p2p_scan_work;
+	struct wpa_radio_work *p2p_listen_work;
+	struct wpa_radio_work *p2p_send_action_work;
+
+	u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
+	struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group
+					* formation */
+	u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+	u8 p2p_ip_addr_info[3 * 4];
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;
@@ -672,7 +751,6 @@
 	int after_wps;
 	int known_wps_freq;
 	unsigned int wps_freq;
-	u16 wps_ap_channel;
 	int wps_fragment_size;
 	int auto_reconnect_disabled;
 
@@ -700,15 +778,16 @@
 	} hw;
 
 	int pno;
+	int pno_sched_pending;
 
 	/* WLAN_REASON_* reason codes. Negative if locally generated. */
 	int disconnect_reason;
 
 	struct ext_password_data *ext_pw;
 
-	struct wpabuf *last_gas_resp;
-	u8 last_gas_addr[ETH_ALEN];
-	u8 last_gas_dialog_token;
+	struct wpabuf *last_gas_resp, *prev_gas_resp;
+	u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN];
+	u8 last_gas_dialog_token, prev_gas_dialog_token;
 
 	unsigned int no_keep_alive:1;
 
@@ -729,6 +808,9 @@
 #endif /* CONFIG_TESTING_GET_GTK */
 
 	unsigned int num_multichan_concurrent;
+	struct wpa_radio_work *connect_work;
+
+	unsigned int ext_work_id;
 };
 
 
@@ -776,6 +858,9 @@
 				    struct wpa_ssid *ssid);
 void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid);
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+					   const char *pkcs11_engine_path,
+					   const char *pkcs11_module_path);
 int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
 			       int ap_scan);
 int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
@@ -807,7 +892,6 @@
 void wpa_supplicant_terminate_proc(struct wpa_global *global);
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 			     const u8 *buf, size_t len);
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -821,7 +905,6 @@
 		    size_t ssid_len);
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -867,6 +950,8 @@
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
+void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
+		     int *freq_array, unsigned int len);
 int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 			   int *freq_array, unsigned int len);
 
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 61a42bd..e8a4b35 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -216,20 +216,38 @@
 }
 
 
-static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+static const char * result_str(enum eapol_supp_result result)
+{
+	switch (result) {
+	case EAPOL_SUPP_RESULT_FAILURE:
+		return "FAILURE";
+	case EAPOL_SUPP_RESULT_SUCCESS:
+		return "SUCCESS";
+	case EAPOL_SUPP_RESULT_EXPECTED_FAILURE:
+		return "EXPECTED_FAILURE";
+	}
+	return "?";
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
+				    enum eapol_supp_result result,
 				    void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	int res, pmk_len;
 	u8 pmk[PMK_LEN];
 
-	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
-		   success ? "" : "un");
+	wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
+		   result_str(result));
 
 	if (wpas_wps_eapol_cb(wpa_s) > 0)
 		return;
 
-	if (!success) {
+	wpa_s->eap_expected_failure = result ==
+		EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+
+	if (result != EAPOL_SUPP_RESULT_SUCCESS) {
 		/*
 		 * Make sure we do not get stuck here waiting for long EAPOL
 		 * timeout if the AP does not disconnect in case of
@@ -238,7 +256,8 @@
 		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
 	}
 
-	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+	if (result != EAPOL_SUPP_RESULT_SUCCESS ||
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
 		return;
 
 	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -560,7 +579,9 @@
 	const u8 *supp_rates, size_t supp_rates_len,
 	const struct ieee80211_ht_capabilities *ht_capab,
 	const struct ieee80211_vht_capabilities *vht_capab,
-	u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
+	u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
+	const u8 *supp_channels, size_t supp_channels_len,
+	const u8 *supp_oper_classes, size_t supp_oper_classes_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct hostapd_sta_add_params params;
@@ -588,6 +609,10 @@
 	params.set = !add;
 	params.ext_capab = ext_capab;
 	params.ext_capab_len = ext_capab_len;
+	params.supp_channels = supp_channels;
+	params.supp_channels_len = supp_channels_len;
+	params.supp_oper_classes = supp_oper_classes;
+	params.supp_oper_classes_len = supp_oper_classes_len;
 
 	return wpa_drv_sta_add(wpa_s, &params);
 }
@@ -611,6 +636,8 @@
 		return WPA_CTRL_REQ_EAP_OTP;
 	else if (os_strcmp(field, "PASSPHRASE") == 0)
 		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	else if (os_strcmp(field, "SIM") == 0)
+		return WPA_CTRL_REQ_SIM;
 	return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -647,6 +674,9 @@
 		*txt = "Private key passphrase";
 		ret = "PASSPHRASE";
 		break;
+	case WPA_CTRL_REQ_SIM:
+		ret = "SIM";
+		break;
 	default:
 		break;
 	}
@@ -918,6 +948,22 @@
 		conf.ssid = ssid->ssid;
 		conf.ssid_len = ssid->ssid_len;
 		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+#ifdef CONFIG_P2P
+		if (ssid->p2p_group && wpa_s->current_bss &&
+		    !wpa_s->p2p_disable_ip_addr_req) {
+			struct wpabuf *p2p;
+			p2p = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+							  P2P_IE_VENDOR_TYPE);
+			if (p2p) {
+				u8 group_capab;
+				group_capab = p2p_get_group_capab(p2p);
+				if (group_capab &
+				    P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION)
+					conf.p2p = 1;
+				wpabuf_free(p2p);
+			}
+		}
+#endif /* CONFIG_P2P */
 	}
 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
new file mode 100644
index 0000000..4e39024
--- /dev/null
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -0,0 +1,28 @@
+/*
+ * wpa_supplicant module tests
+ * Copyright (c) 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"
+
+int wpas_module_tests(void)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "wpa_supplicant module tests");
+
+#ifdef CONFIG_WPS
+	{
+		int wps_module_tests(void);
+		if (wps_module_tests() < 0)
+			ret = -1;
+	}
+#endif /* CONFIG_WPS */
+
+	return ret;
+}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index f6c2fcb..c87fa3d 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -54,6 +54,11 @@
 
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
 {
+#ifdef CONFIG_P2P
+	if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
+		return 1;
+#endif /* CONFIG_P2P */
+
 	if (!wpa_s->wps_success &&
 	    wpa_s->current_ssid &&
 	    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
@@ -260,31 +265,6 @@
 		    ssid->group_cipher != new_ssid->group_cipher)
 			continue;
 
-		if (ssid->passphrase && new_ssid->passphrase) {
-			if (os_strlen(ssid->passphrase) !=
-			    os_strlen(new_ssid->passphrase))
-				continue;
-			if (os_strcmp(ssid->passphrase, new_ssid->passphrase) !=
-			    0)
-				continue;
-		} else if (ssid->passphrase || new_ssid->passphrase)
-			continue;
-
-		if ((ssid->psk_set || new_ssid->psk_set) &&
-		    os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0)
-			continue;
-
-		if (ssid->auth_alg == WPA_ALG_WEP) {
-			if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx)
-				continue;
-			if (os_memcmp(ssid->wep_key, new_ssid->wep_key,
-				      sizeof(ssid->wep_key)))
-				continue;
-			if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len,
-				      sizeof(ssid->wep_key_len)))
-				continue;
-		}
-
 		/* Remove the duplicated older network entry. */
 		wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
 		wpas_notify_network_removed(wpa_s, ssid);
@@ -509,9 +489,6 @@
 
 	wpas_wps_security_workaround(wpa_s, ssid, cred);
 
-	if (cred->ap_channel)
-		wpa_s->wps_ap_channel = cred->ap_channel;
-
 	wpas_wps_remove_dup_network(wpa_s, ssid);
 
 #ifndef CONFIG_NO_CONFIG_WRITE
@@ -882,12 +859,16 @@
 	int id;
 	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
 
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
+
 	prev_current = wpa_s->current_ssid;
 
 	/* Enable the networks disabled during wpas_wps_reassoc */
 	wpas_wps_reenable_networks(wpa_s);
 
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
 
 	/* Remove any existing WPS network from configuration */
 	ssid = wpa_s->conf->ssid;
@@ -927,7 +908,8 @@
 
 
 static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
-					      int registrar, const u8 *bssid)
+					      int registrar, const u8 *dev_addr,
+					      const u8 *bssid)
 {
 	struct wpa_ssid *ssid;
 
@@ -947,6 +929,11 @@
 		return NULL;
 	}
 
+#ifdef CONFIG_P2P
+	if (dev_addr)
+		os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
+#endif /* CONFIG_P2P */
+
 	if (bssid) {
 #ifndef CONFIG_P2P
 		struct wpa_bss *bss;
@@ -1027,13 +1014,17 @@
 
 
 static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
-			     struct wpa_ssid *selected, const u8 *bssid)
+			     struct wpa_ssid *selected, const u8 *bssid,
+			     int freq)
 {
 	struct wpa_bss *bss;
 
 	wpa_s->after_wps = 0;
 	wpa_s->known_wps_freq = 0;
-	if (bssid) {
+	if (freq) {
+		wpa_s->after_wps = 5;
+		wpa_s->wps_freq = freq;
+	} else if (bssid) {
 		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
 		if (bss && bss->freq > 0) {
 			wpa_s->known_wps_freq = 1;
@@ -1049,6 +1040,8 @@
 	wpa_s->normal_scans = 0;
 	wpa_s->wps_success = 0;
 	wpa_s->blacklist_cleared = 0;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
@@ -1058,7 +1051,7 @@
 {
 	struct wpa_ssid *ssid;
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
 	if (ssid == NULL)
 		return -1;
 	ssid->temporary = 1;
@@ -1081,24 +1074,47 @@
 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
 			       wpa_s, NULL);
-	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
 	return 0;
 }
 
 
-int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-		       const char *pin, int p2p_group, u16 dev_pw_id)
+static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr, const u8 *bssid,
+				 const char *pin, int p2p_group, u16 dev_pw_id,
+				 const u8 *peer_pubkey_hash,
+				 const u8 *ssid_val, size_t ssid_len, int freq)
 {
 	struct wpa_ssid *ssid;
-	char val[128];
+	char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
 	unsigned int rpin = 0;
+	char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
 
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
-	if (ssid == NULL)
+	if (bssid && is_zero_ether_addr(bssid))
+		bssid = NULL;
+	ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not add network");
 		return -1;
+	}
 	ssid->temporary = 1;
 	ssid->p2p_group = p2p_group;
+	if (ssid_val) {
+		ssid->ssid = os_malloc(ssid_len);
+		if (ssid->ssid) {
+			os_memcpy(ssid->ssid, ssid_val, ssid_len);
+			ssid->ssid_len = ssid_len;
+		}
+	}
+	if (peer_pubkey_hash) {
+		os_memcpy(hash, " pkhash=", 8);
+		wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
+					   peer_pubkey_hash,
+					   WPS_OOB_PUBKEY_HASH_LEN);
+	} else {
+		hash[0] = '\0';
+	}
 #ifdef CONFIG_P2P
 	if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
 		ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1112,25 +1128,38 @@
 	}
 #endif /* CONFIG_P2P */
 	if (pin)
-		os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
-			    pin, dev_pw_id);
-	else {
+		os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
+			    pin, dev_pw_id, hash);
+	else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
+		os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
+			    dev_pw_id, hash);
+	} else {
 		rpin = wps_generate_pin();
-		os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
-			    rpin, dev_pw_id);
+		os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
+			    rpin, dev_pw_id, hash);
 	}
-	if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+	if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
 		return -1;
+	}
 	if (wpa_s->wps_fragment_size)
 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
 			       wpa_s, NULL);
 	wpa_s->wps_ap_iter = 1;
-	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
 	return rpin;
 }
 
 
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, int p2p_group, u16 dev_pw_id)
+{
+	return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
+				     dev_pw_id, NULL, NULL, 0, 0);
+}
+
+
 /* Cancel the wps pbc/pin requests */
 int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
 {
@@ -1155,8 +1184,13 @@
 	} else {
 		wpas_wps_reenable_networks(wpa_s);
 		wpas_wps_clear_ap_info(wpa_s);
+		if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
+		    0)
+			wpas_clear_wps(wpa_s);
 	}
 
+	wpa_s->after_wps = 0;
+
 	return 0;
 }
 
@@ -1172,7 +1206,7 @@
 	if (!pin)
 		return -1;
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+	ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
 	if (ssid == NULL)
 		return -1;
 	ssid->temporary = 1;
@@ -1200,7 +1234,7 @@
 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
 			       wpa_s, NULL);
-	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
 	return 0;
 }
 
@@ -1291,7 +1325,9 @@
 static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
 			      struct wps_context *wps)
 {
-	wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname);
+	char buf[50];
+	const char *src;
+
 	if (is_nil_uuid(wpa_s->conf->uuid)) {
 		struct wpa_supplicant *first;
 		first = wpa_s->global->ifaces;
@@ -1302,18 +1338,18 @@
 				os_memcpy(wps->uuid,
 					  wpa_s->global->ifaces->wps->uuid,
 					  WPS_UUID_LEN);
-			wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
-				    "interface", wps->uuid, WPS_UUID_LEN);
+			src = "from the first interface";
 		} else {
 			uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
-			wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
-				    "address", wps->uuid, WPS_UUID_LEN);
+			src = "based on MAC address";
 		}
 	} else {
 		os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
-		wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration",
-			    wps->uuid, WPS_UUID_LEN);
+		src = "based on configuration";
 	}
+
+	uuid_bin2str(wps->uuid, buf, sizeof(buf));
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
 }
 
 
@@ -1418,6 +1454,20 @@
 }
 
 
+#ifdef CONFIG_WPS_ER
+static void wpas_wps_nfc_clear(struct wps_context *wps)
+{
+	wps->ap_nfc_dev_pw_id = 0;
+	wpabuf_free(wps->ap_nfc_dh_pubkey);
+	wps->ap_nfc_dh_pubkey = NULL;
+	wpabuf_free(wps->ap_nfc_dh_privkey);
+	wps->ap_nfc_dh_privkey = NULL;
+	wpabuf_free(wps->ap_nfc_dev_pw);
+	wps->ap_nfc_dev_pw = NULL;
+}
+#endif /* CONFIG_WPS_ER */
+
+
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
@@ -1431,6 +1481,7 @@
 #ifdef CONFIG_WPS_ER
 	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
 	wpa_s->wps_er = NULL;
+	wpas_wps_nfc_clear(wpa_s->wps);
 #endif /* CONFIG_WPS_ER */
 
 	wps_registrar_deinit(wpa_s->wps->registrar);
@@ -1952,19 +2003,6 @@
 }
 
 
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid;
-
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-		if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
-			return 1;
-	}
-
-	return 0;
-}
-
-
 void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
 {
 	struct wps_context *wps = wpa_s->wps;
@@ -2090,15 +2128,32 @@
 }
 
 
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
+		       const u8 *bssid,
+		       const struct wpabuf *dev_pw, u16 dev_pw_id,
+		       int p2p_group, const u8 *peer_pubkey_hash,
+		       const u8 *ssid, size_t ssid_len, int freq)
 {
 	struct wps_context *wps = wpa_s->wps;
 	char pw[32 * 2 + 1];
 
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+		dev_pw = wpa_s->conf->wps_nfc_dev_pw;
+		dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+	}
+
 	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
-	    wpa_s->conf->wps_nfc_dh_privkey == NULL ||
-	    wpa_s->conf->wps_nfc_dev_pw == NULL)
+	    wpa_s->conf->wps_nfc_dh_privkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
+			   "cannot start NFC-triggered connection");
 		return -1;
+	}
+
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
+			   "cannot start NFC-triggered connection", dev_pw_id);
+		return -1;
+	}
 
 	dh5_free(wps->dh_ctx);
 	wpabuf_free(wps->dh_pubkey);
@@ -2111,6 +2166,7 @@
 		wps->dh_pubkey = NULL;
 		wpabuf_free(wps->dh_privkey);
 		wps->dh_privkey = NULL;
+		wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
 		return -1;
 	}
 	wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
@@ -2119,22 +2175,25 @@
 		wps->dh_pubkey = NULL;
 		wpabuf_free(wps->dh_privkey);
 		wps->dh_privkey = NULL;
+		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
 		return -1;
 	}
 
-	wpa_snprintf_hex_uppercase(pw, sizeof(pw),
-				   wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
-				   wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
-	return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
-				  wpa_s->conf->wps_nfc_dev_pw_id);
+	if (dev_pw) {
+		wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+					   wpabuf_head(dev_pw),
+					   wpabuf_len(dev_pw));
+	}
+	return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
+				     dev_pw ? pw : NULL,
+				     p2p_group, dev_pw_id, peer_pubkey_hash,
+				     ssid, ssid_len, freq);
 }
 
 
 static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
 			     struct wps_parse_attr *attr)
 {
-	wpa_s->wps_ap_channel = 0;
-
 	/*
 	 * Disable existing networks temporarily to allow the newly learned
 	 * credential to be preferred. Enable the temporarily disabled networks
@@ -2150,12 +2209,8 @@
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 		return 0;
 
-	wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
-		   "based on the received credential added");
-	wpa_s->normal_scans = 0;
-	wpa_supplicant_reinit_autoscan(wpa_s);
-	if (wpa_s->wps_ap_channel) {
-		u16 chan = wpa_s->wps_ap_channel;
+	if (attr->ap_channel) {
+		u16 chan = WPA_GET_BE16(attr->ap_channel);
 		int freq = 0;
 
 		if (chan >= 1 && chan <= 13)
@@ -2166,14 +2221,21 @@
 			freq = 5000 + 5 * chan;
 
 		if (freq) {
-			wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
-				   "AP channel %u -> %u MHz", chan, freq);
+			wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz",
+				   chan, freq);
 			wpa_s->after_wps = 5;
 			wpa_s->wps_freq = freq;
 		}
 	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+		   "based on the received credential added");
+	wpa_s->normal_scans = 0;
+	wpa_supplicant_reinit_autoscan(wpa_s);
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 
 	return 0;
@@ -2217,7 +2279,7 @@
 
 
 int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
-			  const struct wpabuf *data)
+			  const struct wpabuf *data, int forced_freq)
 {
 	const struct wpabuf *wps = data;
 	struct wpabuf *tmp = NULL;
@@ -2230,6 +2292,15 @@
 		/* Assume this contains full NDEF record */
 		tmp = ndef_parse_wifi(data);
 		if (tmp == NULL) {
+#ifdef CONFIG_P2P
+			tmp = ndef_parse_p2p(data);
+			if (tmp) {
+				ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
+							       forced_freq);
+				wpabuf_free(tmp);
+				return ret;
+			}
+#endif /* CONFIG_P2P */
 			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
 			return -1;
 		}
@@ -2242,24 +2313,45 @@
 }
 
 
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr)
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+					  int ndef)
 {
-	if (cr)
-		return ndef_build_wifi_hc(1);
-	return ndef_build_wifi_hr();
+	struct wpabuf *ret;
+
+	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+	    wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+			   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+		return NULL;
+
+	ret = wps_build_nfc_handover_req(wpa_s->wps,
+					 wpa_s->conf->wps_nfc_dh_pubkey);
+
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
 }
 
 
 #ifdef CONFIG_WPS_NFC
-struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s,
-					     int ndef, const char *uuid)
+
+static struct wpabuf *
+wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
+			     const char *uuid)
 {
 #ifdef CONFIG_WPS_ER
 	struct wpabuf *ret;
 	u8 u[UUID_LEN], *use_uuid = NULL;
 	u8 addr[ETH_ALEN], *use_addr = NULL;
+	struct wps_context *wps = wpa_s->wps;
 
-	if (!wpa_s->wps_er)
+	if (wps == NULL)
 		return NULL;
 
 	if (uuid == NULL)
@@ -2271,11 +2363,23 @@
 	else
 		return NULL;
 
-	/*
-	 * Handover Select carrier record for WPS uses the same format as
-	 * configuration token.
-	 */
-	ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
+		if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+				   &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+			return NULL;
+	}
+
+	wpas_wps_nfc_clear(wps);
+	wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+	wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+	wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+	if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+		wpas_wps_nfc_clear(wps);
+		return NULL;
+	}
+
+	ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
+				      use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
 	if (ndef && ret) {
 		struct wpabuf *tmp;
 		tmp = ndef_build_wifi(ret);
@@ -2306,29 +2410,125 @@
 }
 
 
-int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
-				 const struct wpabuf *data)
-{
-	/* TODO */
-	return -1;
-}
-
-
 int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
 				 const struct wpabuf *data)
 {
 	struct wpabuf *wps;
-	int ret;
+	int ret = -1;
+	u16 wsc_len;
+	const u8 *pos;
+	struct wpabuf msg;
+	struct wps_parse_attr attr;
+	u16 dev_pw_id;
+	const u8 *bssid = NULL;
+	int freq = 0;
 
 	wps = ndef_parse_wifi(data);
 	if (wps == NULL)
 		return -1;
 	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
 		   "payload from NFC connection handover");
-	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
-	ret = wpas_wps_nfc_tag_process(wpa_s, wps);
-	wpabuf_free(wps);
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+	if (wpabuf_len(wps) < 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
+			   "Message");
+		goto out;
+	}
+	pos = wpabuf_head(wps);
+	wsc_len = WPA_GET_BE16(pos);
+	if (wsc_len > wpabuf_len(wps) - 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+			   "in Wi-Fi Handover Select Message", wsc_len);
+		goto out;
+	}
+	pos += 2;
 
+	wpa_hexdump(MSG_DEBUG,
+		    "WPS: WSC attributes in Wi-Fi Handover Select Message",
+		    pos, wsc_len);
+	if (wsc_len < wpabuf_len(wps) - 2) {
+		wpa_hexdump(MSG_DEBUG,
+			    "WPS: Ignore extra data after WSC attributes",
+			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+	}
+
+	wpabuf_set(&msg, pos, wsc_len);
+	ret = wps_parse_msg(&msg, &attr);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+			   "Wi-Fi Handover Select Message");
+		goto out;
+	}
+
+	if (attr.oob_dev_password == NULL ||
+	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+			   "included in Wi-Fi Handover Select Message");
+		ret = -1;
+		goto out;
+	}
+
+	if (attr.ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
+			   "Select Message");
+		ret = -1;
+		goto out;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
+
+	if (attr.mac_addr) {
+		bssid = attr.mac_addr;
+		wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
+			   MAC2STR(bssid));
+	}
+
+	if (attr.rf_bands)
+		wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
+
+	if (attr.ap_channel) {
+		u16 chan = WPA_GET_BE16(attr.ap_channel);
+
+		wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
+
+		if (chan >= 1 && chan <= 13 &&
+		    (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
+			freq = 2407 + 5 * chan;
+		else if (chan == 14 &&
+			 (attr.rf_bands == NULL ||
+			  *attr.rf_bands & WPS_RF_24GHZ))
+			freq = 2484;
+		else if (chan >= 30 &&
+			 (attr.rf_bands == NULL ||
+			  *attr.rf_bands & WPS_RF_50GHZ))
+			freq = 5000 + 5 * chan;
+
+		if (freq) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: AP indicated channel %u -> %u MHz",
+				   chan, freq);
+		}
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+		    attr.oob_dev_password, attr.oob_dev_password_len);
+	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+				 WPS_OOB_PUBKEY_HASH_LEN);
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+			   "%u in Wi-Fi Handover Select Message", dev_pw_id);
+		ret = -1;
+		goto out;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
+		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+	ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
+				 attr.oob_dev_password,
+				 attr.ssid, attr.ssid_len, freq);
+
+out:
+	wpabuf_free(wps);
 	return ret;
 }
 
@@ -2343,15 +2543,107 @@
 	return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
 }
 
+
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel)
+{
+	struct wpabuf *wps;
+	int ret = -1;
+	u16 wsc_len;
+	const u8 *pos;
+	struct wpabuf msg;
+	struct wps_parse_attr attr;
+	u16 dev_pw_id;
+
+	/*
+	 * Enrollee/station is always initiator of the NFC connection handover,
+	 * so use the request message here to find Enrollee public key hash.
+	 */
+	wps = ndef_parse_wifi(req);
+	if (wps == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+		   "payload from NFC connection handover");
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+	if (wpabuf_len(wps) < 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+			   "Message");
+		goto out;
+	}
+	pos = wpabuf_head(wps);
+	wsc_len = WPA_GET_BE16(pos);
+	if (wsc_len > wpabuf_len(wps) - 2) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+			   "in rt Wi-Fi Handover Request Message", wsc_len);
+		goto out;
+	}
+	pos += 2;
+
+	wpa_hexdump(MSG_DEBUG,
+		    "WPS: WSC attributes in Wi-Fi Handover Request Message",
+		    pos, wsc_len);
+	if (wsc_len < wpabuf_len(wps) - 2) {
+		wpa_hexdump(MSG_DEBUG,
+			    "WPS: Ignore extra data after WSC attributes",
+			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+	}
+
+	wpabuf_set(&msg, pos, wsc_len);
+	ret = wps_parse_msg(&msg, &attr);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+			   "Wi-Fi Handover Request Message");
+		goto out;
+	}
+
+	if (attr.oob_dev_password == NULL ||
+	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+			   "included in Wi-Fi Handover Request Message");
+		ret = -1;
+		goto out;
+	}
+
+	if (attr.uuid_e == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+			   "Handover Request Message");
+		ret = -1;
+		goto out;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+		    attr.oob_dev_password, attr.oob_dev_password_len);
+	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+				 WPS_OOB_PUBKEY_HASH_LEN);
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+			   "%u in Wi-Fi Handover Request Message", dev_pw_id);
+		ret = -1;
+		goto out;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+	ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
+					     attr.oob_dev_password,
+					     DEV_PW_NFC_CONNECTION_HANDOVER,
+					     NULL, 0, 1);
+
+out:
+	wpabuf_free(wps);
+	return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
-extern int wpa_debug_level;
-
 static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
 {
 	size_t i;
-	struct os_time now;
+	struct os_reltime now;
 
 	if (wpa_debug_level > MSG_DEBUG)
 		return;
@@ -2359,7 +2651,7 @@
 	if (wpa_s->wps_ap == NULL)
 		return;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	for (i = 0; i < wpa_s->num_wps_ap; i++) {
 		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
@@ -2463,11 +2755,14 @@
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
 	struct wps_ap_info *ap;
+
+	wpa_s->after_wps = 0;
+
 	if (!wpa_s->wps_ap_iter)
 		return;
 	ap = wpas_wps_get_ap_info(wpa_s, bssid);
 	if (ap == NULL)
 		return;
 	ap->tries++;
-	os_get_time(&ap->last_attempt);
+	os_get_reltime(&ap->last_attempt);
 }
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 2a212ca..39df2fb 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -60,24 +60,29 @@
 struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
 					     int ndef, const char *uuid);
 int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
 void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
 struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					  int ndef, const char *id_str);
 struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+		       const u8 *bssid,
+		       const struct wpabuf *dev_pw, u16 dev_pw_id,
+		       int p2p_group, const u8 *peer_pubkey_hash,
+		       const u8 *ssid, size_t ssid_len, int freq);
 int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
-			  const struct wpabuf *data);
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr);
+			  const struct wpabuf *data, int forced_freq);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+					  int ndef);
 struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
 					  int ndef, int cr, const char *uuid);
-int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
-				 const struct wpabuf *data);
 int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
 				 const struct wpabuf *data);
 int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
 				 const struct wpabuf *req,
 				 const struct wpabuf *sel);
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel);
 void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_results *scan_res);
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);