am 82c2c233: (-s ours) am 26a545dc: Do not try auto connect mechanism in disconnected state, DO NOT MERGE

* commit '82c2c2331d5d0bccf5d49f03347c9a23285a305b':
  Do not try auto connect mechanism in disconnected state, DO NOT MERGE
diff --git a/Android.mk b/Android.mk
index 76afb77..4a74b24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,3 +11,6 @@
 include $(LOCAL_PATH)/hostapd/Android.mk \
         $(LOCAL_PATH)/wpa_supplicant/Android.mk
 endif
+ifeq ($(WPA_SUPPLICANT_VERSION),VER_2_1_DEVEL)
+include $(call all-subdir-makefiles)
+endif
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0d97a21..7ecbc65 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -57,3 +57,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_cli_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/hostapd/Android.mk b/hostapd/Android.mk
index 1c2e1f5..1054dc0 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -367,6 +367,13 @@
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+L_CFLAGS += -DEAP_SERVER_EKE
+OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
 ifdef CONFIG_EAP_VENDOR_TEST
 L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
 OBJS += src/eap_server/eap_server_vendor_test.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 8404e0c..a30a244 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -323,6 +323,13 @@
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+CFLAGS += -DEAP_SERVER_EKE
+OBJS += ../src/eap_server/eap_server_eke.o ../src/eap_common/eap_eke_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
 ifdef CONFIG_EAP_VENDOR_TEST
 CFLAGS += -DEAP_SERVER_VENDOR_TEST
 OBJS += ../src/eap_server/eap_server_vendor_test.o
@@ -824,6 +831,10 @@
 LIBS_h += -lsqlite3
 endif
 
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+endif
+
 ALL=hostapd hostapd_cli
 
 all: verify_config $(ALL)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 12d627a..8e6f35a 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -83,7 +83,7 @@
 			return -1;
 		}
 
-		vlan = os_malloc(sizeof(*vlan));
+		vlan = os_zalloc(sizeof(*vlan));
 		if (vlan == NULL) {
 			wpa_printf(MSG_ERROR, "Out of memory while reading "
 				   "VLAN interfaces from '%s'", fname);
@@ -91,7 +91,6 @@
 			return -1;
 		}
 
-		os_memset(vlan, 0, sizeof(*vlan));
 		vlan->vlan_id = vlan_id;
 		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
 		if (bss->vlan_tail)
@@ -711,14 +710,14 @@
 }
 
 
-static int hostapd_parse_rates(int **rate_list, char *val)
+static int hostapd_parse_intlist(int **int_list, char *val)
 {
 	int *list;
 	int count;
 	char *pos, *end;
 
-	os_free(*rate_list);
-	*rate_list = NULL;
+	os_free(*int_list);
+	*int_list = NULL;
 
 	pos = val;
 	count = 0;
@@ -745,7 +744,7 @@
 	}
 	list[count] = -1;
 
-	*rate_list = list;
+	*int_list = list;
 	return 0;
 }
 
@@ -1224,6 +1223,12 @@
 		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;
@@ -1684,6 +1689,9 @@
 				   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) {
+			os_strlcpy(bss->vlan_bridge, pos,
+			           sizeof(bss->vlan_bridge));
 		} else if (os_strcmp(buf, "wds_bridge") == 0) {
 			os_strlcpy(bss->wds_bridge, pos,
 				   sizeof(bss->wds_bridge));
@@ -1785,6 +1793,8 @@
 			conf->country[2] = ' ';
 		} else if (os_strcmp(buf, "ieee80211d") == 0) {
 			conf->ieee80211d = atoi(pos);
+		} else if (os_strcmp(buf, "ieee80211h") == 0) {
+			conf->ieee80211h = atoi(pos);
 		} else if (os_strcmp(buf, "ieee8021x") == 0) {
 			bss->ieee802_1x = atoi(pos);
 		} else if (os_strcmp(buf, "eapol_version") == 0) {
@@ -1823,6 +1833,9 @@
 			bss->private_key_passwd = os_strdup(pos);
 		} else if (os_strcmp(buf, "check_crl") == 0) {
 			bss->check_crl = atoi(pos);
+		} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
+			os_free(bss->ocsp_stapling_response);
+			bss->ocsp_stapling_response = os_strdup(pos);
 		} else if (os_strcmp(buf, "dh_file") == 0) {
 			os_free(bss->dh_file);
 			bss->dh_file = os_strdup(pos);
@@ -2349,13 +2362,14 @@
 			} else
 				conf->send_probe_response = val;
 		} else if (os_strcmp(buf, "supported_rates") == 0) {
-			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+			if (hostapd_parse_intlist(&conf->supported_rates, pos))
+			{
 				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
 					   "list", line);
 				errors++;
 			}
 		} else if (os_strcmp(buf, "basic_rates") == 0) {
-			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+			if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
 				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
 					   "list", line);
 				errors++;
@@ -2620,6 +2634,9 @@
 			bss->upc = os_strdup(pos);
 		} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
 			bss->pbc_in_m1 = atoi(pos);
+		} else if (os_strcmp(buf, "server_id") == 0) {
+			os_free(bss->server_id);
+			bss->server_id = os_strdup(pos);
 #ifdef CONFIG_WPS_NFC
 		} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
 			bss->wps_nfc_dev_pw_id = atoi(pos);
@@ -2876,6 +2893,26 @@
 			bss->hs20_operating_class = oper_class;
 			bss->hs20_operating_class_len = oper_class_len;
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_TESTING_OPTIONS
+#define PARSE_TEST_PROBABILITY(_val)					\
+		} else if (os_strcmp(buf, #_val) == 0) {		\
+			char *end;					\
+									\
+			conf->_val = strtod(pos, &end);			\
+			if (*end || conf->_val < 0.0d ||		\
+			    conf->_val > 1.0d) {			\
+				wpa_printf(MSG_ERROR,			\
+					   "Line %d: Invalid value '%s'", \
+					   line, pos);			\
+				errors++;				\
+				return errors;				\
+			}
+		PARSE_TEST_PROBABILITY(ignore_probe_probability)
+		PARSE_TEST_PROBABILITY(ignore_auth_probability)
+		PARSE_TEST_PROBABILITY(ignore_assoc_probability)
+		PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
+		PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+#endif /* CONFIG_TESTING_OPTIONS */
 		} else if (os_strcmp(buf, "vendor_elements") == 0) {
 			struct wpabuf *elems;
 			size_t len = os_strlen(pos);
@@ -2907,7 +2944,7 @@
 		} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
 			bss->sae_anti_clogging_threshold = atoi(pos);
 		} else if (os_strcmp(buf, "sae_groups") == 0) {
-			if (hostapd_parse_rates(&bss->sae_groups, pos)) {
+			if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
 				wpa_printf(MSG_ERROR, "Line %d: Invalid "
 					   "sae_groups value '%s'", line, pos);
 				return 1;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 2153329..021cbe5 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -29,6 +29,7 @@
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "config_file.h"
@@ -537,15 +538,25 @@
 					   const char *cmd)
 {
 	u8 addr[ETH_ALEN];
-	const char *url;
+	const char *url, *timerstr;
 	u8 buf[1000], *pos;
 	struct ieee80211_mgmt *mgmt;
 	size_t url_len;
+	int disassoc_timer;
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
-	url = cmd + 17;
-	if (*url != ' ')
+
+	timerstr = cmd + 17;
+	if (*timerstr != ' ')
+		return -1;
+	timerstr++;
+	disassoc_timer = atoi(timerstr);
+	if (disassoc_timer < 0 || disassoc_timer > 65535)
+		return -1;
+
+	url = os_strchr(timerstr, ' ');
+	if (url == NULL)
 		return -1;
 	url++;
 	url_len = os_strlen(url);
@@ -564,8 +575,9 @@
 	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(0);
-	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+	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;
 
@@ -580,6 +592,41 @@
 		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;
 }
 
@@ -1035,7 +1082,7 @@
 }
 
 
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
 				      const char *txt, size_t len)
 {
 	struct hostapd_data *hapd = ctx;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index b5ddca3..c288f46 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -117,6 +117,9 @@
 # Trusted Network Connect (EAP-TNC)
 #CONFIG_EAP_TNC=y
 
+# EAP-EKE for the integrated EAP server
+#CONFIG_EAP_EKE=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
@@ -267,3 +270,11 @@
 
 # Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
 #CONFIG_SQLITE=y
+
+# Testing options
+# This can be used to enable some testing options (see also the example
+# configuration file) that are really useful only for testing clients that
+# connect to this hostapd. These options allow, for example, to drop a
+# certain percentage of probe requests or auth/(re)assoc frames.
+#
+#CONFIG_TESTING_OPTIONS=y
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index 0a7ff91..981e539 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -134,5 +134,10 @@
 		ret = eap_server_pwd_register();
 #endif /* EAP_SERVER_PWD */
 
+#ifdef EAP_SERVER_EKE
+	if (ret == 0)
+		ret = eap_server_eke_register();
+#endif /* EAP_SERVER_EKE */
+
 	return ret;
 }
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 17bb7ed..68c4069 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -105,6 +105,12 @@
 # (default: 0 = disabled)
 #ieee80211d=1
 
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=1
+
 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
 # ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
 # specify band)
@@ -660,6 +666,11 @@
 # Passphrase for private key
 #private_key_passwd=secret passphrase
 
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
 # Enable CRL verification.
 # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
 # valid CRL signed by the CA is required to be included in the ca_cert file.
@@ -671,6 +682,20 @@
 # 2 = check all CRLs in the certificate path
 #check_crl=1
 
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+#	-no_nonce \
+#	-CAfile /etc/hostapd.ca.pem \
+#	-issuer /etc/hostapd.ca.pem \
+#	-cert /etc/hostapd.server.pem \
+#	-url http://ocsp.example.com:8888/ \
+#	-respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
 # dh_file: File path to DH/DSA parameters file (in PEM format)
 # This is an optional configuration file for setting parameters for an
 # ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -814,9 +839,8 @@
 # is used for the stations. This information is parsed from following RADIUS
 # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
 # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
-# VLANID as a string). vlan_file option below must be configured if dynamic
-# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
-# used to set static client MAC address to VLAN ID mapping.
+# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
+# be used to set static client MAC address to VLAN ID mapping.
 # 0 = disabled (default)
 # 1 = option; use default interface if RADIUS server does not include VLAN ID
 # 2 = required; reject authentication if RADIUS server does not include VLAN ID
@@ -828,6 +852,8 @@
 # multiple BSSIDs or SSIDs. Each line in this text file is defining a new
 # interface and the line must include VLAN ID and interface name separated by
 # white space (space or tab).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
 #vlan_file=/etc/hostapd.vlan
 
 # Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -837,6 +863,12 @@
 # to the bridge.
 #vlan_tagged_interface=eth0
 
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
 # When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
 # to know how to name it.
 # 0 = vlan<XXX>, e.g., vlan1
@@ -1521,6 +1553,28 @@
 # channels 36-48):
 #hs20_operating_class=5173
 
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+
 ##### Multiple BSSID support ##################################################
 #
 # Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 1537275..7071594 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -593,14 +593,14 @@
 	char buf[300];
 	int res;
 
-	if (argc < 2) {
-		printf("Invalid 'ess_disassoc' command - two arguments (STA "
-		       "addr and URL) are needed\n");
+	if (argc < 3) {
+		printf("Invalid 'ess_disassoc' command - three arguments (STA "
+		       "addr, disassoc timer, and URL) are needed\n");
 		return -1;
 	}
 
-	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
-			  argv[0], argv[1]);
+	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
+			  argv[0], argv[1], argv[2]);
 	if (res < 0 || res >= (int) sizeof(buf))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
diff --git a/hostapd/main.c b/hostapd/main.c
index d2ec1a5..90e5966 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -194,6 +194,8 @@
 	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) {
@@ -277,6 +279,7 @@
 		iface->extended_capa = capa.extended_capa;
 		iface->extended_capa_mask = capa.extended_capa_mask;
 		iface->extended_capa_len = capa.extended_capa_len;
+		iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
 	}
 
 	return 0;
@@ -301,13 +304,18 @@
 			iface->bss[0]->conf->logger_stdout_level--;
 	}
 
-	if (iface->conf->bss[0].iface[0] != 0 ||
-	    hostapd_drv_none(iface->bss[0])) {
-		if (hostapd_driver_init(iface) ||
-			hostapd_setup_interface(iface)) {
-			hostapd_interface_deinit_free(iface);
-			return NULL;
-		}
+	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);
+		hostapd_interface_deinit_free(iface);
+		return NULL;
+	}
+
+	if (hostapd_driver_init(iface) ||
+	    hostapd_setup_interface(iface)) {
+		hostapd_interface_deinit_free(iface);
+		return NULL;
 	}
 
 	return iface;
@@ -647,22 +655,28 @@
 		}
 	}
 
-	if (hostapd_global_init(&interfaces, entropy_file))
+	if (hostapd_global_init(&interfaces, entropy_file)) {
+		wpa_printf(MSG_ERROR, "Failed to initilize global context");
 		return -1;
+	}
 
 	/* Initialize interfaces */
 	for (i = 0; i < interfaces.count; i++) {
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
 							     argv[optind + i],
 							     debug);
-		if (!interfaces.iface[i])
+		if (!interfaces.iface[i]) {
+			wpa_printf(MSG_ERROR, "Failed to initialize interface");
 			goto out;
+		}
 	}
 
 	hostapd_global_ctrl_iface_init(&interfaces);
 
-	if (hostapd_global_run(&interfaces, daemonize, pid_file))
+	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+		wpa_printf(MSG_ERROR, "Failed to start eloop");
 		goto out;
+	}
 
 	ret = 0;
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 922f564..fbc1ee0 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -163,6 +163,14 @@
 	conf->ap_table_max_size = 255;
 	conf->ap_table_expiration_time = 60;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	conf->ignore_probe_probability = 0.0d;
+	conf->ignore_auth_probability = 0.0d;
+	conf->ignore_assoc_probability = 0.0d;
+	conf->ignore_reassoc_probability = 0.0d;
+	conf->corrupt_gtk_rekey_mic_probability = 0.0d;
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	return conf;
 }
 
@@ -432,6 +440,7 @@
 	os_free(conf->server_cert);
 	os_free(conf->private_key);
 	os_free(conf->private_key_passwd);
+	os_free(conf->ocsp_stapling_response);
 	os_free(conf->dh_file);
 	os_free(conf->pac_opaque_encr_key);
 	os_free(conf->eap_fast_a_id);
@@ -523,6 +532,8 @@
 	wpabuf_free(conf->vendor_elements);
 
 	os_free(conf->sae_groups);
+
+	os_free(conf->server_id);
 }
 
 
@@ -598,11 +609,23 @@
 }
 
 
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
 {
 	struct hostapd_vlan *v = vlan;
 	while (v) {
 		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+			return 1;
+		v = v->next;
+	}
+	return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+	struct hostapd_vlan *v = vlan;
+	while (v) {
+		if (v->vlan_id == vlan_id)
 			return v->ifname;
 		v = v->next;
 	}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index d9ef984..a744ba6 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -180,6 +180,7 @@
 struct hostapd_bss_config {
 	char iface[IFNAMSIZ + 1];
 	char bridge[IFNAMSIZ + 1];
+	char vlan_bridge[IFNAMSIZ + 1];
 	char wds_bridge[IFNAMSIZ + 1];
 
 	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -294,6 +295,7 @@
 	char *private_key;
 	char *private_key_passwd;
 	int check_crl;
+	char *ocsp_stapling_response;
 	char *dh_file;
 	u8 *pac_opaque_encr_key;
 	u8 *eap_fast_a_id;
@@ -373,6 +375,7 @@
 	struct wpabuf *wps_nfc_dev_pw;
 #endif /* CONFIG_WPS */
 	int pbc_in_m1;
+	char *server_id;
 
 #define P2P_ENABLED BIT(0)
 #define P2P_GROUP_OWNER BIT(1)
@@ -498,6 +501,8 @@
 
 	int ieee80211d;
 
+	int ieee80211h; /* DFS */
+
 	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
 
 	/*
@@ -520,6 +525,14 @@
 	u8 vht_oper_chwidth;
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	double ignore_probe_probability;
+	double ignore_auth_probability;
+	double ignore_assoc_probability;
+	double ignore_reassoc_probability;
+	double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -536,6 +549,7 @@
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   const u8 *addr, const u8 *prev_psk);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
 					int vlan_id);
 struct hostapd_radius_attr *
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ceb7e68..70fab55 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -173,6 +173,14 @@
 	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
 }
 
+static inline int hostapd_drv_set_acl(struct hostapd_data *hapd,
+				      struct hostapd_acl_params *params)
+{
+	if (hapd->driver == NULL || hapd->driver->set_acl == NULL)
+		return 0;
+	return hapd->driver->set_acl(hapd->drv_priv, params);
+}
+
 static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
 				     struct wpa_driver_ap_params *params)
 {
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index d66d97e..68ad4dc 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -111,6 +111,7 @@
 	srv.eap_req_id_text = conf->eap_req_id_text;
 	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
 	srv.pwd_group = conf->pwd_group;
+	srv.server_id = conf->server_id ? conf->server_id : "hostapd";
 #ifdef CONFIG_RADIUS_TEST
 	srv.dump_msk_file = conf->dump_msk_file;
 #endif /* CONFIG_RADIUS_TEST */
@@ -148,6 +149,8 @@
 		params.private_key = hapd->conf->private_key;
 		params.private_key_passwd = hapd->conf->private_key_passwd;
 		params.dh_file = hapd->conf->dh_file;
+		params.ocsp_stapling_response =
+			hapd->conf->ocsp_stapling_response;
 
 		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
 			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4c47c75..2f4ba23 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -485,9 +485,30 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	    supp_rates_11b_only(&elems)) {
+		/* Indicates support for 11b rates only */
+		wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
+			   MACSTR " with only 802.11b rates",
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+#endif /* CONFIG_P2P */
+
 	/* TODO: verify that supp_rates contains at least one matching rate
 	 * with AP configuration */
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->iconf->ignore_probe_probability > 0.0d &&
+	    drand48() < hapd->iconf->ignore_probe_probability) {
+		wpa_printf(MSG_INFO,
+			   "TESTING: ignoring probe request from " MACSTR,
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
 				      &resp_len);
 	if (resp == NULL)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 6d22d49..fa4b5e4 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -85,6 +85,7 @@
 
 	sta = ap_get_sta(hapd, addr);
 	if (sta) {
+		ap_sta_no_session_timeout(hapd, sta);
 		accounting_sta_stop(hapd, sta);
 
 		/*
@@ -469,7 +470,7 @@
 	if (!sta) {
 		sta = ap_sta_add(hapd, rx_auth->peer);
 		if (sta == NULL) {
-			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 			goto fail;
 		}
 	}
@@ -730,6 +731,9 @@
 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
 			level = MSG_EXCESSIVE;
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
+			level = MSG_EXCESSIVE;
 	}
 
 	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a0ac38c..780b2e2 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -837,6 +837,74 @@
 }
 
 
+static int hostapd_set_acl_list(struct hostapd_data *hapd,
+				struct mac_acl_entry *mac_acl,
+				int n_entries, u8 accept_acl)
+{
+	struct hostapd_acl_params *acl_params;
+	int i, err;
+
+	acl_params = os_zalloc(sizeof(*acl_params) +
+			       (n_entries * sizeof(acl_params->mac_acl[0])));
+	if (!acl_params)
+		return -ENOMEM;
+
+	for (i = 0; i < n_entries; i++)
+		os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
+			  ETH_ALEN);
+
+	acl_params->acl_policy = accept_acl;
+	acl_params->num_mac_acl = n_entries;
+
+	err = hostapd_drv_set_acl(hapd, acl_params);
+
+	os_free(acl_params);
+
+	return err;
+}
+
+
+static void hostapd_set_acl(struct hostapd_data *hapd)
+{
+	struct hostapd_config *conf = hapd->iconf;
+	int err;
+	u8 accept_acl;
+
+	if (hapd->iface->drv_max_acl_mac_addrs == 0)
+		return;
+	if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+		return;
+
+	if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+		if (conf->bss->num_accept_mac) {
+			accept_acl = 1;
+			err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
+						   conf->bss->num_accept_mac,
+						   accept_acl);
+			if (err) {
+				wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+				return;
+			}
+		} 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) {
+			accept_acl = 0;
+			err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
+						   conf->bss->num_deny_mac,
+						   accept_acl);
+			if (err) {
+				wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+				return;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+		}
+	}
+}
+
+
 static int setup_interface(struct hostapd_iface *iface)
 {
 	struct hostapd_data *hapd = iface->bss[0];
@@ -962,6 +1030,8 @@
 
 	ap_list_init(iface);
 
+	hostapd_set_acl(hapd);
+
 	if (hostapd_driver_commit(hapd) < 0) {
 		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
 			   "configuration", __func__);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 9a3bb68..75d9c66 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -25,6 +25,7 @@
 union wps_event_data;
 
 struct hostapd_iface;
+struct hostapd_dynamic_iface;
 
 struct hapd_interfaces {
 	int (*reload_config)(struct hostapd_iface *iface);
@@ -37,11 +38,13 @@
 	int (*driver_init)(struct hostapd_iface *iface);
 
 	size_t count;
+	size_t count_dynamic;
 	int global_ctrl_sock;
 	char *global_iface_path;
 	char *global_iface_name;
 	gid_t ctrl_iface_group;
 	struct hostapd_iface **iface;
+	struct hostapd_dynamic_iface **dynamic_iface;
 };
 
 
@@ -233,6 +236,8 @@
 	const u8 *extended_capa, *extended_capa_mask;
 	unsigned int extended_capa_len;
 
+	unsigned int drv_max_acl_mac_addrs;
+
 	struct hostapd_hw_modes *hw_features;
 	int num_hw_features;
 	struct hostapd_hw_modes *current_mode;
@@ -273,6 +278,16 @@
 	void (*scan_cb)(struct hostapd_iface *iface);
 };
 
+/**
+ * struct hostapd_dynamic_iface - hostapd per dynamically allocated
+ * or added interface data structure
+ */
+struct hostapd_dynamic_iface {
+	char parent[IFNAMSIZ + 1];
+	char iface[IFNAMSIZ + 1];
+	unsigned int usage;
+};
+
 /* hostapd.c */
 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
 			       int (*cb)(struct hostapd_iface *iface,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 8baa15e..5503af1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -557,6 +557,16 @@
 		return;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->iconf->ignore_auth_probability > 0.0d &&
+	    drand48() < hapd->iconf->ignore_auth_probability) {
+		wpa_printf(MSG_INFO,
+			   "TESTING: ignoring auth frame from " MACSTR,
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
 	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
 	status_code = le_to_host16(mgmt->u.auth.status_code);
@@ -635,13 +645,12 @@
 
 	sta = ap_sta_add(hapd, mgmt->sa);
 	if (!sta) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 		goto fail;
 	}
 
 	if (vlan_id > 0) {
-		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       vlan_id) == NULL) {
+		if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
 				       "%d received from RADIUS server",
@@ -1226,6 +1235,26 @@
 		return;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (reassoc) {
+		if (hapd->iconf->ignore_reassoc_probability > 0.0d &&
+		    drand48() < hapd->iconf->ignore_reassoc_probability) {
+			wpa_printf(MSG_INFO,
+				   "TESTING: ignoring reassoc request from "
+				   MACSTR, MAC2STR(mgmt->sa));
+			return;
+		}
+	} else {
+		if (hapd->iconf->ignore_assoc_probability > 0.0d &&
+		    drand48() < hapd->iconf->ignore_assoc_probability) {
+			wpa_printf(MSG_INFO,
+				   "TESTING: ignoring assoc request from "
+				   MACSTR, MAC2STR(mgmt->sa));
+			return;
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (reassoc) {
 		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
 		listen_interval = le_to_host16(
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a832a73..3554e8b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -399,15 +399,13 @@
 
 	/* Save station identity for future RADIUS packets */
 	os_free(sm->identity);
-	sm->identity = os_malloc(identity_len + 1);
+	sm->identity = (u8 *) dup_binstr(identity, identity_len);
 	if (sm->identity == NULL) {
 		sm->identity_len = 0;
 		return;
 	}
 
-	os_memcpy(sm->identity, identity, identity_len);
 	sm->identity_len = identity_len;
-	sm->identity[identity_len] = '\0';
 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
 		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
 	sm->dot1xAuthEapolRespIdFramesRx++;
@@ -1272,13 +1270,10 @@
 				    NULL) < 0)
 		return;
 
-	identity = os_malloc(len + 1);
+	identity = (u8 *) dup_binstr(buf, len);
 	if (identity == NULL)
 		return;
 
-	os_memcpy(identity, buf, len);
-	identity[len] = '\0';
-
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
 		       "User-Name from Access-Accept '%s'",
@@ -1443,8 +1438,7 @@
 			sta->vlan_id = radius_msg_get_vlanid(msg);
 		}
 		if (sta->vlan_id > 0 &&
-		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       sta->vlan_id)) {
+		    hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -1834,6 +1828,13 @@
 	conf.fragment_size = hapd->conf->fragment_size;
 	conf.pwd_group = hapd->conf->pwd_group;
 	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+	if (hapd->conf->server_id) {
+		conf.server_id = (const u8 *) hapd->conf->server_id;
+		conf.server_id_len = os_strlen(hapd->conf->server_id);
+	} else {
+		conf.server_id = (const u8 *) "hostapd";
+		conf.server_id_len = 7;
+	}
 
 	os_memset(&cb, 0, sizeof(cb));
 	cb.eapol_send = ieee802_1x_eapol_send;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index d27fd30..40972e9 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -48,8 +48,8 @@
 }
 
 
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
-				   struct rsn_pmksa_cache_entry *entry)
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+			    struct rsn_pmksa_cache_entry *entry)
 {
 	struct rsn_pmksa_cache_entry *pos, *prev;
 
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index d473f3f..aa90024 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -55,5 +55,7 @@
 		    const u8 *aa, const u8 *pmkid);
 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
 			       struct eapol_state_machine *eapol);
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+			    struct rsn_pmksa_cache_entry *entry);
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index cbafb47..833f1b2 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -283,6 +283,7 @@
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 	unsigned long next_time = 0;
+	int reason;
 
 	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
 		   __func__, MAC2STR(sta->addr), sta->flags,
@@ -378,9 +379,11 @@
 				hapd, sta->addr,
 				WLAN_REASON_PREV_AUTH_NOT_VALID);
 		} else {
-			hostapd_drv_sta_disassoc(
-				hapd, sta->addr,
-				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+			reason = (sta->timeout_next == STA_DISASSOC) ?
+				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+				WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+			hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
 		}
 	}
 
@@ -394,6 +397,7 @@
 				       hapd, sta);
 		break;
 	case STA_DISASSOC:
+	case STA_DISASSOC_FROM_CLI:
 		ap_sta_set_authorized(hapd, sta, 0);
 		sta->flags &= ~WLAN_STA_ASSOC;
 		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -405,14 +409,16 @@
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "disassociated due to "
 			       "inactivity");
+		reason = (sta->timeout_next == STA_DISASSOC) ?
+			WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+			WLAN_REASON_PREV_AUTH_NOT_VALID;
 		sta->timeout_next = STA_DEAUTH;
 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
 			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
 			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
 		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
 				       hapd, sta);
-		mlme_disassociate_indication(
-			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+		mlme_disassociate_indication(hapd, sta, reason);
 		break;
 	case STA_DEAUTH:
 	case STA_REMOVE:
@@ -855,6 +861,7 @@
 			   int authorized)
 {
 	const u8 *dev_addr = NULL;
+	char buf[100];
 #ifdef CONFIG_P2P
 	u8 addr[ETH_ALEN];
 #endif /* CONFIG_P2P */
@@ -871,44 +878,29 @@
 		dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
 #endif /* CONFIG_P2P */
 
+	if (dev_addr)
+		os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
+			    MAC2STR(sta->addr), MAC2STR(dev_addr));
+	else
+		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
+
 	if (authorized) {
-		if (dev_addr)
-			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
-				MACSTR " p2p_dev_addr=" MACSTR,
-				MAC2STR(sta->addr), MAC2STR(dev_addr));
-		else
-			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
-				MACSTR, MAC2STR(sta->addr));
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s", buf);
+
 		if (hapd->msg_ctx_parent &&
-		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_CONNECTED MACSTR " p2p_dev_addr="
-				MACSTR,
-				MAC2STR(sta->addr), MAC2STR(dev_addr));
-		else if (hapd->msg_ctx_parent &&
-			 hapd->msg_ctx_parent != hapd->msg_ctx)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+		    hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+					  AP_STA_CONNECTED "%s", buf);
 
 		sta->flags |= WLAN_STA_AUTHORIZED;
 	} else {
-		if (dev_addr)
-			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
-				MACSTR " p2p_dev_addr=" MACSTR,
-				MAC2STR(sta->addr), MAC2STR(dev_addr));
-		else
-			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
-				MACSTR, MAC2STR(sta->addr));
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
+
 		if (hapd->msg_ctx_parent &&
-		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
-				MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
-		else if (hapd->msg_ctx_parent &&
-			 hapd->msg_ctx_parent != hapd->msg_ctx)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_DISCONNECTED MACSTR,
-				MAC2STR(sta->addr));
+		    hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+					  AP_STA_DISCONNECTED "%s", buf);
+
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
 	}
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 32ea46e..f8f5a83 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -62,7 +62,8 @@
 	u8 previous_ap[6];
 
 	enum {
-		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE,
+		STA_DISASSOC_FROM_CLI
 	} timeout_next;
 
 	u16 deauth_reason;
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 7b1a9e6..70affda 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -480,6 +480,123 @@
 #endif /* CONFIG_VLAN_NETLINK */
 
 
+/**
+ * Increase the usage counter for given parent/ifname combination.
+ * If create is set, then this iface is added to the global list.
+ * Returns
+ * 	-1 on error
+ * 	0 if iface is not in list
+ * 	1 if iface is in list (was there or has been added)
+ */
+static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
+				  int create, struct hostapd_data *hapd)
+{
+	size_t i;
+	struct hostapd_dynamic_iface *j = NULL, **tmp;
+	struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
+
+	if (!parent)
+		parent = "";
+
+	for (i = 0; i < hapd_global->count_dynamic; i++) {
+		j = hapd_global->dynamic_iface[i];
+		if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+		    os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+			break;
+	}
+	if (i < hapd_global->count_dynamic) {
+		j->usage++;
+		return 1;
+	}
+
+	/* new entry required */
+	if (!create)
+		return 0;
+
+	j = os_zalloc(sizeof(*j));
+	if (!j)
+		return -1;
+	os_strlcpy(j->iface, ifname, sizeof(j->iface));
+	os_strlcpy(j->parent, parent, sizeof(j->parent));
+
+	tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
+			       sizeof(*hapd_global->dynamic_iface));
+	if (!tmp) {
+		wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
+			   __func__);
+		return -1;
+	}
+	hapd_global->count_dynamic++;
+	hapd_global->dynamic_iface = tmp;
+	hapd_global->dynamic_iface[i] = j;
+
+	return 1;
+}
+
+
+/**
+ * Decrease the usage counter for given ifname.
+ * Returns
+ *     -1 on error or if iface was not found
+ *     0 if iface was found and is still present
+ *     1 if iface was removed from global list
+ */
+static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
+				  struct hostapd_data *hapd)
+{
+	size_t i;
+	struct hostapd_dynamic_iface *j = NULL, **tmp;
+	struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
+
+	if (!parent)
+		parent = "";
+
+	for (i = 0; i < hapd_glob->count_dynamic; i++) {
+		j = hapd_glob->dynamic_iface[i];
+		if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+		    os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+			break;
+	}
+
+	if (i == hapd_glob->count_dynamic) {
+		/*
+		 * Interface not in global list. This can happen if alloc in
+		 * _get_ failed.
+		 */
+		return -1;
+	}
+
+	if (j->usage > 0) {
+		j->usage--;
+		return 0;
+	}
+
+	os_free(j);
+	for (; i < hapd_glob->count_dynamic - 1; i++)
+		hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
+	hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
+	hapd_glob->count_dynamic--;
+
+	if (hapd_glob->count_dynamic == 0) {
+		os_free(hapd_glob->dynamic_iface);
+		hapd_glob->dynamic_iface = NULL;
+		return 1;
+	}
+
+	tmp = os_realloc_array(hapd_glob->dynamic_iface,
+			       hapd_glob->count_dynamic,
+			       sizeof(*hapd_glob->dynamic_iface));
+	if (!tmp) {
+		wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
+			   __func__);
+		return -1;
+	}
+	hapd_glob->dynamic_iface = tmp;
+
+	return 1;
+}
+
+
 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
 	char vlan_ifname[IFNAMSIZ];
@@ -487,16 +604,29 @@
 	struct hostapd_vlan *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
 	int vlan_naming = hapd->conf->ssid.vlan_naming;
+	int ret;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
 	while (vlan) {
 		if (os_strcmp(ifname, vlan->ifname) == 0) {
 
-			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-				    vlan->vlan_id);
+			if (hapd->conf->vlan_bridge[0]) {
+				os_snprintf(br_name, sizeof(br_name), "%s%d",
+					    hapd->conf->vlan_bridge,
+					    vlan->vlan_id);
+			} else if (tagged_interface) {
+				os_snprintf(br_name, sizeof(br_name),
+				            "br%s.%d", tagged_interface,
+					    vlan->vlan_id);
+			} else {
+				os_snprintf(br_name, sizeof(br_name),
+				            "brvlan%d", vlan->vlan_id);
+			}
 
-			if (!br_addbr(br_name))
+			ret = br_addbr(br_name);
+			if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
+			                           hapd))
 				vlan->clean |= DVLAN_CLEAN_BR;
 
 			ifconfig_up(br_name);
@@ -514,17 +644,24 @@
 						    "vlan%d", vlan->vlan_id);
 
 				ifconfig_up(tagged_interface);
-				if (!vlan_add(tagged_interface, vlan->vlan_id,
-					      vlan_ifname))
+				ret = vlan_add(tagged_interface, vlan->vlan_id,
+					      vlan_ifname);
+				if (hapd_get_dynamic_iface(NULL, vlan_ifname,
+				                           ret == 0, hapd))
 					vlan->clean |= DVLAN_CLEAN_VLAN;
 
-				if (!br_addif(br_name, vlan_ifname))
+				ret = br_addif(br_name, vlan_ifname);
+				if (hapd_get_dynamic_iface(br_name,
+							   vlan_ifname,
+							   ret == 0, hapd))
 					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
 
 				ifconfig_up(vlan_ifname);
 			}
 
-			if (!br_addif(br_name, ifname))
+			ret = br_addif(br_name, ifname);
+			if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
+						   hapd))
 				vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
 
 			ifconfig_up(ifname);
@@ -550,10 +687,21 @@
 
 	while (vlan) {
 		if (os_strcmp(ifname, vlan->ifname) == 0) {
-			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-				    vlan->vlan_id);
+			if (hapd->conf->vlan_bridge[0]) {
+				os_snprintf(br_name, sizeof(br_name), "%s%d",
+					    hapd->conf->vlan_bridge,
+					    vlan->vlan_id);
+			} else if (tagged_interface) {
+				os_snprintf(br_name, sizeof(br_name),
+				            "br%s.%d", tagged_interface,
+					    vlan->vlan_id);
+			} else {
+				os_snprintf(br_name, sizeof(br_name),
+				            "brvlan%d", vlan->vlan_id);
+			}
 
-			if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+			if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
+			    hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
 				br_delif(br_name, vlan->ifname);
 
 			if (tagged_interface) {
@@ -567,15 +715,20 @@
 					os_snprintf(vlan_ifname,
 						    sizeof(vlan_ifname),
 						    "vlan%d", vlan->vlan_id);
-				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+				if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
+				    hapd_put_dynamic_iface(br_name, vlan_ifname,
+							   hapd))
 					br_delif(br_name, vlan_ifname);
 				ifconfig_down(vlan_ifname);
 
-				if (vlan->clean & DVLAN_CLEAN_VLAN)
+				if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
+				    hapd_put_dynamic_iface(NULL, vlan_ifname,
+							   hapd))
 					vlan_rem(vlan_ifname);
 			}
 
 			if ((vlan->clean & DVLAN_CLEAN_BR) &&
+			    hapd_put_dynamic_iface(NULL, br_name, hapd) &&
 			    br_getnumports(br_name) == 0) {
 				ifconfig_down(br_name);
 				br_delbr(br_name);
@@ -837,6 +990,27 @@
 	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
+	if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+	    !hapd->conf->vlan) {
+		/* dynamic vlans enabled but no (or empty) vlan_file given */
+		struct hostapd_vlan *vlan;
+		vlan = os_zalloc(sizeof(*vlan));
+		if (vlan == NULL) {
+			wpa_printf(MSG_ERROR, "Out of memory while assigning "
+				   "VLAN interfaces");
+			return -1;
+		}
+
+		vlan->vlan_id = VLAN_ID_WILDCARD;
+		os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+			    hapd->conf->iface);
+		if (hapd->conf->vlan_tail)
+			hapd->conf->vlan_tail->next = vlan;
+		else
+			hapd->conf->vlan = vlan;
+		hapd->conf->vlan_tail = vlan;
+	}
+
 	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
 		return -1;
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 4f1f6fb..83cc857 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1232,7 +1232,7 @@
 	else
 		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
 
-	pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+	pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
 
 	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
 		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
@@ -1347,6 +1347,16 @@
 		}
 		wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
 				  key->key_mic);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (!pairwise &&
+		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+		    drand48() <
+		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"Corrupting group EAPOL-Key Key MIC");
+			key->key_mic[0]++;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
 	}
 
 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
@@ -2934,6 +2944,22 @@
 }
 
 
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr)
+{
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+		return;
+	pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+	if (pmksa) {
+		wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+			   MACSTR " based on request", MAC2STR(sta_addr));
+		pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+	}
+}
+
+
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 465eec6..ebfe86f 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -160,6 +160,9 @@
 #endif /* CONFIG_IEEE80211R */
 	int disable_gtk;
 	int ap_mlme;
+#ifdef CONFIG_TESTING_OPTIONS
+	double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 typedef enum {
@@ -260,6 +263,8 @@
 			       const u8 *pmk, size_t len, const u8 *sta_addr,
 			       int session_timeout,
 			       struct eapol_state_machine *eapol);
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr);
 int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
 void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
 				  struct wpa_state_machine *sm, int ack);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index ccb3f82..1bb5d97 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1166,6 +1166,8 @@
 
 	/* RRB - Forward action frame to the target AP */
 	frame = os_malloc(sizeof(*frame) + len);
+	if (frame == NULL)
+		return -1;
 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
 	frame->packet_type = FT_PACKET_REQUEST;
 	frame->action_length = host_to_le16(len);
@@ -1216,6 +1218,10 @@
 	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
 
 	frame = os_malloc(sizeof(*frame) + rlen);
+	if (frame == NULL) {
+		os_free(resp_ies);
+		return -1;
+	}
 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
 	frame->packet_type = FT_PACKET_RESPONSE;
 	frame->action_length = host_to_le16(rlen);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index fdaaaff..e2be1ea 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -28,6 +28,7 @@
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+				  struct hostapd_config *iconf,
 				  struct wpa_auth_config *wconf)
 {
 	os_memset(wconf, 0, sizeof(*wconf));
@@ -74,6 +75,10 @@
 #ifdef CONFIG_HS20
 	wconf->disable_gtk = conf->disable_dgaf;
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_TESTING_OPTIONS
+	wconf->corrupt_gtk_rekey_mic_probability =
+		iconf->corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
 }
 
 
@@ -509,7 +514,7 @@
 	const u8 *wpa_ie;
 	size_t wpa_ie_len;
 
-	hostapd_wpa_auth_conf(hapd->conf, &_conf);
+	hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
 	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
 		_conf.tx_status = 1;
 	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
@@ -583,7 +588,7 @@
 void hostapd_reconfig_wpa(struct hostapd_data *hapd)
 {
 	struct wpa_auth_config wpa_auth_conf;
-	hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
+	hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf);
 	wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
 }
 
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 98fadda..aab8ac6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2012, 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.
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "defs.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
 
@@ -486,3 +487,61 @@
 
 	return 0;
 }
+
+
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
+{
+	enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
+
+	if (freq >= 2412 && freq <= 2472) {
+		mode = HOSTAPD_MODE_IEEE80211G;
+		*channel = (freq - 2407) / 5;
+	} else if (freq == 2484) {
+		mode = HOSTAPD_MODE_IEEE80211B;
+		*channel = 14;
+	} else if (freq >= 4900 && freq < 5000) {
+		mode = HOSTAPD_MODE_IEEE80211A;
+		*channel = (freq - 4000) / 5;
+	} else if (freq >= 5000 && freq < 5900) {
+		mode = HOSTAPD_MODE_IEEE80211A;
+		*channel = (freq - 5000) / 5;
+	} else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+		mode = HOSTAPD_MODE_IEEE80211AD;
+		*channel = (freq - 56160) / 2160;
+	}
+
+	return mode;
+}
+
+
+static int is_11b(u8 rate)
+{
+	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+	int num_11b = 0, num_others = 0;
+	int i;
+
+	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+		return 0;
+
+	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+		if (is_11b(elems->supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+	     i++) {
+		if (is_11b(elems->ext_supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	return num_11b > 0 && num_others == 0;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 55fa49d..68c6b96 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -99,5 +99,8 @@
 
 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
 			  const char *name, const char *val);
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index f782c86..137c309 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -549,6 +549,14 @@
 					 * Entries (optional) */
 					u8 variable[0];
 				} STRUCT_PACKED bss_tm_resp;
+				struct {
+					u8 action; /* 6 */
+					u8 dialog_token;
+					u8 query_reason;
+					/* BSS Transition Candidate List
+					 * Entries (optional) */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_query;
 			} u;
 		} STRUCT_PACKED action;
 	} u;
@@ -1049,6 +1057,28 @@
 #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
 #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
 
+/* IEEE Std 802.11-2012 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+	WNM_BSS_TM_ACCEPT = 0,
+	WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+	WNM_BSS_TM_REJECT_UNDESIRED = 4,
+	WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+	WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+	WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+	WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
+
+#define WNM_NEIGHBOR_TSF                         1
+#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING    2
+#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE    3
+#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION    4
+#define WNM_NEIGHBOR_BEARING                     5
+#define WNM_NEIGHBOR_MEASUREMENT_PILOT          66
+#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
+#define WNM_NEIGHBOR_MULTIPLE_BSSID             71
+
 /* 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)
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a8cf6be..c3afbfd 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -335,7 +335,6 @@
 #endif /* CONFIG_IEEE80211R */
 
 
-#ifndef CONFIG_NO_WPA2
 static int rsn_selector_to_bitfield(const u8 *s)
 {
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -384,7 +383,6 @@
 #endif /* CONFIG_SAE */
 	return 0;
 }
-#endif /* CONFIG_NO_WPA2 */
 
 
 /**
@@ -397,7 +395,6 @@
 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 			 struct wpa_ie_data *data)
 {
-#ifndef CONFIG_NO_WPA2
 	const struct rsn_ie_hdr *hdr;
 	const u8 *pos;
 	int left;
@@ -551,9 +548,6 @@
 	}
 
 	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 58cbe6a..d9a7509 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -82,6 +82,9 @@
 	int tries = 0;
 	int flags;
 
+	if (ctrl_path == NULL)
+		return NULL;
+
 	ctrl = os_malloc(sizeof(*ctrl));
 	if (ctrl == NULL)
 		return NULL;
@@ -126,13 +129,27 @@
 #ifdef ANDROID
 	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
 	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+
+	if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
+		if (socket_local_client_connect(
+			    ctrl->s, ctrl_path + 9,
+			    ANDROID_SOCKET_NAMESPACE_RESERVED,
+			    SOCK_DGRAM) < 0) {
+			close(ctrl->s);
+			unlink(ctrl->local.sun_path);
+			os_free(ctrl);
+			return NULL;
+		}
+		return ctrl;
+	}
+
 	/*
 	 * If the ctrl_path isn't an absolute pathname, assume that
 	 * it's the name of a socket in the Android reserved namespace.
 	 * Otherwise, it's a normal UNIX domain socket appearing in the
 	 * filesystem.
 	 */
-	if (ctrl_path != NULL && *ctrl_path != '/') {
+	if (*ctrl_path != '/') {
 		char buf[21];
 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
 		if (socket_local_client_connect(
@@ -149,12 +166,18 @@
 #endif /* ANDROID */
 
 	ctrl->dest.sun_family = AF_UNIX;
-	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
-			 sizeof(ctrl->dest.sun_path));
-	if (res >= sizeof(ctrl->dest.sun_path)) {
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
+	if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
+		ctrl->dest.sun_path[0] = '\0';
+		os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
+			   sizeof(ctrl->dest.sun_path) - 1);
+	} else {
+		res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
+				 sizeof(ctrl->dest.sun_path));
+		if (res >= sizeof(ctrl->dest.sun_path)) {
+			close(ctrl->s);
+			os_free(ctrl);
+			return NULL;
+		}
 	}
 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
 		    sizeof(ctrl->dest)) < 0) {
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index dbabe8c..0c05a41 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -44,6 +44,8 @@
 #define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
 /** EAP TLS certificate chain validation error */
 #define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+/** EAP status */
+#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
 /** EAP authentication completed successfully */
 #define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
 /** EAP authentication failed (EAP-Failure received) */
@@ -134,6 +136,9 @@
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
 
+/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
+#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
+
 #define INTERWORKING_AP "INTERWORKING-AP "
 #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
 
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index b61e439..2fdaa02 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface definition
- * Copyright (c) 2004-2010, 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.
@@ -82,6 +82,8 @@
 #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 #define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+#define TLS_CONN_REQUEST_OCSP BIT(3)
+#define TLS_CONN_REQUIRE_OCSP BIT(4)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -117,6 +119,8 @@
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
  * @flags: Parameter options (TLS_CONN_*)
+ * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
+ *	or %NULL if OCSP is not enabled
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
  * and tls_global_set_params().
@@ -153,6 +157,7 @@
 	const char *ca_cert_id;
 
 	unsigned int flags;
+	const char *ocsp_stapling_response;
 };
 
 
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index e226f1a..d27af0a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2011, 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.
@@ -34,6 +34,10 @@
 #define OPENSSL_d2i_TYPE unsigned char **
 #endif
 
+#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
+#define OPENSSL_SUPPORTS_CTX_APP_DATA
+#endif
+
 #ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
 #ifdef SSL_OP_NO_TICKET
 /*
@@ -61,19 +65,28 @@
 }
 #endif /* ANDROID */
 
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
 static int tls_openssl_ref_count = 0;
 
-struct tls_global {
+struct tls_context {
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
 	void *cb_ctx;
 	int cert_in_cb;
+	char *ocsp_stapling_response;
 };
 
-static struct tls_global *tls_global = NULL;
+static struct tls_context *tls_global = NULL;
 
 
 struct tls_connection {
+	struct tls_context *context;
 	SSL *ssl;
 	BIO *ssl_in, *ssl_out;
 #ifndef OPENSSL_NO_ENGINE
@@ -97,9 +110,26 @@
 	u8 srv_cert_hash[32];
 
 	unsigned int flags;
+
+	X509 *peer_cert;
+	X509 *peer_issuer;
 };
 
 
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+	struct tls_context *context = os_zalloc(sizeof(*context));
+	if (context == NULL)
+		return NULL;
+	if (conf) {
+		context->event_cb = conf->event_cb;
+		context->cb_ctx = conf->cb_ctx;
+		context->cert_in_cb = conf->cert_in_cb;
+	}
+	return context;
+}
+
+
 #ifdef CONFIG_NO_STDOUT_DEBUG
 
 static void _tls_show_errors(void)
@@ -525,6 +555,7 @@
 		wpa_printf(MSG_DEBUG, "SSL: %s:%s",
 			   str, SSL_state_string_long(ssl));
 	} else if (where & SSL_CB_ALERT) {
+		struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
 		wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
 			   where & SSL_CB_READ ?
 			   "read (remote end reported an error)" :
@@ -532,21 +563,19 @@
 			   SSL_alert_type_string_long(ret),
 			   SSL_alert_desc_string_long(ret));
 		if ((ret >> 8) == SSL3_AL_FATAL) {
-			struct tls_connection *conn =
-				SSL_get_app_data((SSL *) ssl);
 			if (where & SSL_CB_READ)
 				conn->read_alerts++;
 			else
 				conn->write_alerts++;
 		}
-		if (tls_global->event_cb != NULL) {
+		if (conn->context->event_cb != NULL) {
 			union tls_event_data ev;
+			struct tls_context *context = conn->context;
 			os_memset(&ev, 0, sizeof(ev));
 			ev.alert.is_local = !(where & SSL_CB_READ);
 			ev.alert.type = SSL_alert_type_string_long(ret);
 			ev.alert.description = SSL_alert_desc_string_long(ret);
-			tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
-					     &ev);
+			context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
 		}
 	} else if (where & SSL_CB_EXIT && ret <= 0) {
 		wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
@@ -704,17 +733,12 @@
 void * tls_init(const struct tls_config *conf)
 {
 	SSL_CTX *ssl;
+	struct tls_context *context;
 
 	if (tls_openssl_ref_count == 0) {
-		tls_global = os_zalloc(sizeof(*tls_global));
-		if (tls_global == NULL)
+		tls_global = context = tls_context_new(conf);
+		if (context == NULL)
 			return NULL;
-		if (conf) {
-			tls_global->event_cb = conf->event_cb;
-			tls_global->cb_ctx = conf->cb_ctx;
-			tls_global->cert_in_cb = conf->cert_in_cb;
-		}
-
 #ifdef CONFIG_FIPS
 #ifdef OPENSSL_FIPS
 		if (conf && conf->fips_mode) {
@@ -760,14 +784,33 @@
 #endif /* OPENSSL_NO_RC2 */
 		PKCS12_PBE_add();
 #endif  /* PKCS12_FUNCS */
+	} else {
+		context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+		/* Newer OpenSSL can store app-data per-SSL */
+		context = tls_context_new(conf);
+		if (context == NULL)
+			return NULL;
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 	}
 	tls_openssl_ref_count++;
 
 	ssl = SSL_CTX_new(TLSv1_method());
-	if (ssl == NULL)
+	if (ssl == NULL) {
+		tls_openssl_ref_count--;
+		if (tls_openssl_ref_count == 0) {
+			os_free(tls_global);
+			tls_global = NULL;
+		} else if (context != tls_global) {
+			os_free(context);
+		}
 		return NULL;
+	}
 
 	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+	SSL_CTX_set_app_data(ssl, context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 
 #ifndef OPENSSL_NO_ENGINE
 	if (conf &&
@@ -793,6 +836,11 @@
 void tls_deinit(void *ssl_ctx)
 {
 	SSL_CTX *ssl = ssl_ctx;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+	struct tls_context *context = SSL_CTX_get_app_data(ssl);
+	if (context != tls_global)
+		os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 	SSL_CTX_free(ssl);
 
 	tls_openssl_ref_count--;
@@ -804,6 +852,8 @@
 		ERR_remove_state(0);
 		ERR_free_strings();
 		EVP_cleanup();
+		os_free(tls_global->ocsp_stapling_response);
+		tls_global->ocsp_stapling_response = NULL;
 		os_free(tls_global);
 		tls_global = NULL;
 	}
@@ -936,6 +986,10 @@
 	SSL_CTX *ssl = ssl_ctx;
 	struct tls_connection *conn;
 	long options;
+	struct tls_context *context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+	context = SSL_CTX_get_app_data(ssl);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
 
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
@@ -948,6 +1002,7 @@
 		return NULL;
 	}
 
+	conn->context = context;
 	SSL_set_app_data(conn->ssl, conn);
 	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
 		SSL_OP_SINGLE_DH_USE;
@@ -1148,8 +1203,9 @@
 {
 	union tls_event_data ev;
 	struct wpabuf *cert = NULL;
+	struct tls_context *context = conn->context;
 
-	if (tls_global->event_cb == NULL)
+	if (context->event_cb == NULL)
 		return;
 
 	cert = get_x509_cert(err_cert);
@@ -1160,7 +1216,7 @@
 	ev.cert_fail.subject = subject;
 	ev.cert_fail.reason_txt = err_str;
 	ev.cert_fail.cert = cert;
-	tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
 	wpabuf_free(cert);
 }
 
@@ -1171,15 +1227,16 @@
 {
 	struct wpabuf *cert = NULL;
 	union tls_event_data ev;
+	struct tls_context *context = conn->context;
 #ifdef CONFIG_SHA256
 	u8 hash[32];
 #endif /* CONFIG_SHA256 */
 
-	if (tls_global->event_cb == NULL)
+	if (context->event_cb == NULL)
 		return;
 
 	os_memset(&ev, 0, sizeof(ev));
-	if (conn->cert_probe || tls_global->cert_in_cb) {
+	if (conn->cert_probe || context->cert_in_cb) {
 		cert = get_x509_cert(err_cert);
 		ev.peer_cert.cert = cert;
 	}
@@ -1197,7 +1254,7 @@
 #endif /* CONFIG_SHA256 */
 	ev.peer_cert.depth = depth;
 	ev.peer_cert.subject = subject;
-	tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
 	wpabuf_free(cert);
 }
 
@@ -1209,6 +1266,7 @@
 	int err, depth;
 	SSL *ssl;
 	struct tls_connection *conn;
+	struct tls_context *context;
 	char *match, *altmatch;
 	const char *err_str;
 
@@ -1222,6 +1280,13 @@
 	conn = SSL_get_app_data(ssl);
 	if (conn == NULL)
 		return 0;
+
+	if (depth == 0)
+		conn->peer_cert = err_cert;
+	else if (depth == 1)
+		conn->peer_issuer = err_cert;
+
+	context = conn->context;
 	match = conn->subject_match;
 	altmatch = conn->altsubject_match;
 
@@ -1304,9 +1369,9 @@
 				       TLS_FAIL_SERVER_CHAIN_PROBE);
 	}
 
-	if (preverify_ok && tls_global->event_cb != NULL)
-		tls_global->event_cb(tls_global->cb_ctx,
-				     TLS_CERT_CHAIN_SUCCESS, NULL);
+	if (preverify_ok && context->event_cb != NULL)
+		context->event_cb(context->cb_ctx,
+				  TLS_CERT_CHAIN_SUCCESS, NULL);
 
 	return preverify_ok;
 }
@@ -2702,11 +2767,187 @@
 }
 
 
+#ifdef HAVE_OCSP
+
+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;
+	int res;
+
+	if (wpa_debug_level > MSG_DEBUG)
+		return;
+
+	out = BIO_new(BIO_s_mem());
+	if (!out)
+		return;
+
+	OCSP_RESPONSE_print(out, rsp, 0);
+	rlen = BIO_ctrl_pending(out);
+	txt = os_malloc(rlen + 1);
+	if (!txt) {
+		BIO_free(out);
+		return;
+	}
+
+	res = BIO_read(out, txt, rlen);
+	if (res > 0) {
+		txt[res] = '\0';
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
+	}
+	os_free(txt);
+	BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+	struct tls_connection *conn = arg;
+	const unsigned char *p;
+	int len, status, reason;
+	OCSP_RESPONSE *rsp;
+	OCSP_BASICRESP *basic;
+	OCSP_CERTID *id;
+	ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+
+	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+	if (!p) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+	if (!rsp) {
+		wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+		return 0;
+	}
+
+	ocsp_debug_print_resp(rsp);
+
+	status = OCSP_response_status(rsp);
+	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+		wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+			   status, OCSP_response_status_str(status));
+		return 0;
+	}
+
+	basic = OCSP_response_get1_basic(rsp);
+	if (!basic) {
+		wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+		return 0;
+	}
+
+	status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx),
+				   0);
+	if (status <= 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"OpenSSL: OCSP response failed verification");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	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");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+	if (!id) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+				   &this_update, &next_update)) {
+		wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+			   (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
+			   " (OCSP not required)");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+	}
+
+	if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"OpenSSL: OCSP status times invalid");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	OCSP_BASICRESP_free(basic);
+	OCSP_RESPONSE_free(rsp);
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+		   OCSP_cert_status_str(status));
+
+	if (status == V_OCSP_CERTSTATUS_GOOD)
+		return 1;
+	if (status == V_OCSP_CERTSTATUS_REVOKED)
+		return 0;
+	if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+		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");
+	return 1;
+}
+
+
+static int ocsp_status_cb(SSL *s, void *arg)
+{
+	char *tmp;
+	char *resp;
+	size_t len;
+
+	if (tls_global->ocsp_stapling_response == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
+		return SSL_TLSEXT_ERR_OK;
+	}
+
+	resp = os_readfile(tls_global->ocsp_stapling_response, &len);
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
+		/* TODO: Build OCSPResponse with responseStatus = internalError
+		 */
+		return SSL_TLSEXT_ERR_OK;
+	}
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
+	tmp = OPENSSL_malloc(len);
+	if (tmp == NULL) {
+		os_free(resp);
+		return SSL_TLSEXT_ERR_ALERT_FATAL;
+	}
+
+	os_memcpy(tmp, resp, len);
+	os_free(resp);
+	SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
+
+	return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* HAVE_OCSP */
+
+
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
 {
 	int ret;
 	unsigned long err;
+	SSL_CTX *ssl_ctx = tls_ctx;
 
 	if (conn == NULL)
 		return -1;
@@ -2770,10 +3011,20 @@
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
 	else
 		SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		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);
+	}
+#endif /* HAVE_OCSP */
+
 	conn->flags = params->flags;
 
 	tls_get_errors(tls_ctx);
@@ -2812,10 +3063,23 @@
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+#ifdef SSL_CTX_clear_options
 	else
 		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+	SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
+	SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
+	os_free(tls_global->ocsp_stapling_response);
+	if (params->ocsp_stapling_response)
+		tls_global->ocsp_stapling_response =
+			os_strdup(params->ocsp_stapling_response);
+	else
+		tls_global->ocsp_stapling_response = NULL;
+#endif /* HAVE_OCSP */
+
 	return 0;
 }
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 14b64a6..0604fef 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -29,6 +29,12 @@
 #define HOSTAPD_CHAN_HT40MINUS 0x00000020
 #define HOSTAPD_CHAN_HT40 0x00000040
 
+#define HOSTAPD_CHAN_DFS_UNKNOWN 0x00000000
+#define HOSTAPD_CHAN_DFS_USABLE 0x00000100
+#define HOSTAPD_CHAN_DFS_UNAVAILABLE 0x00000200
+#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
+#define HOSTAPD_CHAN_DFS_MASK 0x00000300
+
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -824,7 +830,7 @@
  * it cannot be used for P2P group operations or non-P2P purposes.
  */
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
-/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+/* This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
 /* Driver supports concurrent operations on multiple channels */
 #define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
@@ -866,6 +872,10 @@
 #define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
 /* Driver supports IBSS (Ad-hoc) mode */
 #define WPA_DRIVER_FLAGS_IBSS				0x08000000
+/* Driver supports radar detection */
+#define WPA_DRIVER_FLAGS_RADAR				0x10000000
+/* Driver supports a dedicated interface for P2P Device */
+#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
 	unsigned int flags;
 
 	int max_scan_ssids;
@@ -898,6 +908,8 @@
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
 	unsigned int probe_resp_offloads;
 
+	unsigned int max_acl_mac_addrs;
+
 	/**
 	 * extended_capa - extended capabilities in driver/device
 	 *
@@ -958,6 +970,16 @@
 	int bandwidth;
 };
 
+struct mac_address {
+	u8 addr[ETH_ALEN];
+};
+
+struct hostapd_acl_params {
+	u8 acl_policy;
+	unsigned int num_mac_acl;
+	struct mac_address mac_acl[0];
+};
+
 enum wpa_driver_if_type {
 	/**
 	 * WPA_IF_STATION - Station mode interface
@@ -993,7 +1015,13 @@
 	 * WPA_IF_P2P_GROUP - P2P Group interface (will become either
 	 * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
 	 */
-	WPA_IF_P2P_GROUP
+	WPA_IF_P2P_GROUP,
+
+	/**
+	 * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+	 * abstracted P2P Device function in the driver
+	 */
+	WPA_IF_P2P_DEVICE
 };
 
 struct wpa_init_params {
@@ -1070,6 +1098,17 @@
 	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
 };
 
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+	CHAN_WIDTH_20_NOHT,
+	CHAN_WIDTH_20,
+	CHAN_WIDTH_40,
+	CHAN_WIDTH_80,
+	CHAN_WIDTH_80P80,
+	CHAN_WIDTH_160,
+	CHAN_WIDTH_UNKNOWN
+};
+
 /**
  * struct wpa_signal_info - Information about channel signal quality
  */
@@ -1077,8 +1116,12 @@
 	u32 frequency;
 	int above_threshold;
 	int current_signal;
+	int avg_signal;
 	int current_noise;
 	int current_txrate;
+	enum chan_width chanwidth;
+	int center_frq1;
+	int center_frq2;
 };
 
 /**
@@ -1588,6 +1631,16 @@
 	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
 
 	/**
+	 * set_acl - Set ACL in AP mode
+	 * @priv: Private driver interface data
+	 * @params: Parameters to configure ACL
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is used only for the drivers which support MAC address ACL.
+	 */
+	int (*set_acl)(void *priv, struct hostapd_acl_params *params);
+
+	/**
 	 * hapd_init - Initialize driver interface (hostapd only)
 	 * @hapd: Pointer to hostapd context
 	 * @params: Configuration for the driver wrapper
@@ -2658,6 +2711,25 @@
 	 * avoid frequency conflict in single channel concurrency.
 	 */
 	int (*switch_channel)(void *priv, unsigned int freq);
+
+	/**
+	 * start_dfs_cac - Listen for radar interference on the channel
+	 * @priv: Private driver interface data
+	 * @freq: Frequency (in MHz) of the channel
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*start_dfs_cac)(void *priv, int freq);
+
+	/**
+	 * stop_ap - Removes beacon from AP
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This optional function can be used to disable AP mode related
+	 * configuration. Unlike deinit_ap, it does not change to station
+	 * mode.
+	 */
+	int (*stop_ap)(void *priv);
 };
 
 
@@ -3111,7 +3183,38 @@
 	 * with the specified client (for example, max client reached, etc.) in
 	 * AP mode.
 	 */
-	EVENT_CONNECT_FAILED_REASON
+	EVENT_CONNECT_FAILED_REASON,
+
+	/**
+	 * EVENT_RADAR_DETECTED - Notify of radar detection
+	 *
+	 * A radar has been detected on the supplied frequency, hostapd should
+	 * react accordingly (e.g., change channel).
+	 */
+	EVENT_DFS_RADAR_DETECTED,
+
+	/**
+	 * EVENT_CAC_FINISHED - Notify that channel availability check has been completed
+	 *
+	 * After a successful CAC, the channel can be marked clear and used.
+	 */
+	EVENT_DFS_CAC_FINISHED,
+
+	/**
+	 * EVENT_CAC_ABORTED - Notify that channel availability check has been aborted
+	 *
+	 * The CAC was not successful, and the channel remains in the previous
+	 * state. This may happen due to a radar beeing detected or other
+	 * external influences.
+	 */
+	EVENT_DFS_CAC_ABORTED,
+
+	/**
+	 * EVENT_DFS_CAC_NOP_FINISHED - Notify that non-occupancy period is over
+	 *
+	 * The channel which was previously unavailable is now available again.
+	 */
+	EVENT_DFS_NOP_FINISHED
 };
 
 
@@ -3749,6 +3852,14 @@
 			BLOCKED_CLIENT
 		} code;
 	} connect_failed_reason;
+
+	/**
+	 * struct dfs_event - Data for radar detected events
+	 * @freq: Frequency of the channel in MHz
+	 */
+	struct dfs_event {
+		int freq;
+	} dfs_event;
 };
 
 /**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 565a01b..12ccc14 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -80,6 +80,10 @@
 	E2S(CH_SWITCH);
 	E2S(WNM);
 	E2S(CONNECT_FAILED_REASON);
+	E2S(DFS_RADAR_DETECTED);
+	E2S(DFS_CAC_FINISHED);
+	E2S(DFS_CAC_ABORTED);
+	E2S(DFS_NOP_FINISHED);
 	}
 
 	return "UNKNOWN";
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 7af3317..4656c1b 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -2110,14 +2110,8 @@
 		dlen = dpos - desc;
 	else
 		dlen = os_strlen(desc);
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc, dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
+	drv->adapter_desc = dup_binstr(desc, dlen);
 	os_free(b);
-
 	if (drv->adapter_desc == NULL)
 		return -1;
 
@@ -2284,14 +2278,8 @@
 	} else {
 		dlen = os_strlen(desc[i]);
 	}
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc[i], dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
+	drv->adapter_desc = dup_binstr(desc[i], dlen);
 	os_free(names);
-
 	if (drv->adapter_desc == NULL)
 		return -1;
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c59d5bf..bcd0a94 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -157,6 +157,8 @@
 struct nl80211_global {
 	struct dl_list interfaces;
 	int if_add_ifindex;
+	u64 if_add_wdevid;
+	int if_add_wdevid_set;
 	struct netlink_data *netlink;
 	struct nl_cb *nl_cb;
 	struct nl_handle *nl;
@@ -183,12 +185,14 @@
 	struct wpa_driver_nl80211_data *drv;
 	struct i802_bss *next;
 	int ifindex;
+	u64 wdev_id;
 	char ifname[IFNAMSIZ + 1];
 	char brname[IFNAMSIZ];
 	unsigned int beacon_set:1;
 	unsigned int added_if_into_bridge:1;
 	unsigned int added_bridge:1;
 	unsigned int in_deinit:1;
+	unsigned int wdev_id_set:1;
 
 	u8 addr[ETH_ALEN];
 
@@ -225,7 +229,9 @@
 	struct nl_cb *nl_cb;
 
 	u8 auth_bssid[ETH_ALEN];
+	u8 auth_attempt_bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
+	u8 prev_bssid[ETH_ALEN];
 	int associated;
 	u8 ssid[32];
 	size_t ssid_len;
@@ -247,6 +253,7 @@
 	unsigned int retry_auth:1;
 	unsigned int use_monitor:1;
 	unsigned int ignore_next_local_disconnect:1;
+	unsigned int allow_p2p_device:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
@@ -355,6 +362,117 @@
 	struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+	switch (cmd) {
+	C2S(NL80211_CMD_UNSPEC)
+	C2S(NL80211_CMD_GET_WIPHY)
+	C2S(NL80211_CMD_SET_WIPHY)
+	C2S(NL80211_CMD_NEW_WIPHY)
+	C2S(NL80211_CMD_DEL_WIPHY)
+	C2S(NL80211_CMD_GET_INTERFACE)
+	C2S(NL80211_CMD_SET_INTERFACE)
+	C2S(NL80211_CMD_NEW_INTERFACE)
+	C2S(NL80211_CMD_DEL_INTERFACE)
+	C2S(NL80211_CMD_GET_KEY)
+	C2S(NL80211_CMD_SET_KEY)
+	C2S(NL80211_CMD_NEW_KEY)
+	C2S(NL80211_CMD_DEL_KEY)
+	C2S(NL80211_CMD_GET_BEACON)
+	C2S(NL80211_CMD_SET_BEACON)
+	C2S(NL80211_CMD_START_AP)
+	C2S(NL80211_CMD_STOP_AP)
+	C2S(NL80211_CMD_GET_STATION)
+	C2S(NL80211_CMD_SET_STATION)
+	C2S(NL80211_CMD_NEW_STATION)
+	C2S(NL80211_CMD_DEL_STATION)
+	C2S(NL80211_CMD_GET_MPATH)
+	C2S(NL80211_CMD_SET_MPATH)
+	C2S(NL80211_CMD_NEW_MPATH)
+	C2S(NL80211_CMD_DEL_MPATH)
+	C2S(NL80211_CMD_SET_BSS)
+	C2S(NL80211_CMD_SET_REG)
+	C2S(NL80211_CMD_REQ_SET_REG)
+	C2S(NL80211_CMD_GET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+	C2S(NL80211_CMD_GET_REG)
+	C2S(NL80211_CMD_GET_SCAN)
+	C2S(NL80211_CMD_TRIGGER_SCAN)
+	C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCAN_ABORTED)
+	C2S(NL80211_CMD_REG_CHANGE)
+	C2S(NL80211_CMD_AUTHENTICATE)
+	C2S(NL80211_CMD_ASSOCIATE)
+	C2S(NL80211_CMD_DEAUTHENTICATE)
+	C2S(NL80211_CMD_DISASSOCIATE)
+	C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+	C2S(NL80211_CMD_REG_BEACON_HINT)
+	C2S(NL80211_CMD_JOIN_IBSS)
+	C2S(NL80211_CMD_LEAVE_IBSS)
+	C2S(NL80211_CMD_TESTMODE)
+	C2S(NL80211_CMD_CONNECT)
+	C2S(NL80211_CMD_ROAM)
+	C2S(NL80211_CMD_DISCONNECT)
+	C2S(NL80211_CMD_SET_WIPHY_NETNS)
+	C2S(NL80211_CMD_GET_SURVEY)
+	C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+	C2S(NL80211_CMD_SET_PMKSA)
+	C2S(NL80211_CMD_DEL_PMKSA)
+	C2S(NL80211_CMD_FLUSH_PMKSA)
+	C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+	C2S(NL80211_CMD_REGISTER_FRAME)
+	C2S(NL80211_CMD_FRAME)
+	C2S(NL80211_CMD_FRAME_TX_STATUS)
+	C2S(NL80211_CMD_SET_POWER_SAVE)
+	C2S(NL80211_CMD_GET_POWER_SAVE)
+	C2S(NL80211_CMD_SET_CQM)
+	C2S(NL80211_CMD_NOTIFY_CQM)
+	C2S(NL80211_CMD_SET_CHANNEL)
+	C2S(NL80211_CMD_SET_WDS_PEER)
+	C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+	C2S(NL80211_CMD_JOIN_MESH)
+	C2S(NL80211_CMD_LEAVE_MESH)
+	C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+	C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+	C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+	C2S(NL80211_CMD_GET_WOWLAN)
+	C2S(NL80211_CMD_SET_WOWLAN)
+	C2S(NL80211_CMD_START_SCHED_SCAN)
+	C2S(NL80211_CMD_STOP_SCHED_SCAN)
+	C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+	C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+	C2S(NL80211_CMD_PMKSA_CANDIDATE)
+	C2S(NL80211_CMD_TDLS_OPER)
+	C2S(NL80211_CMD_TDLS_MGMT)
+	C2S(NL80211_CMD_UNEXPECTED_FRAME)
+	C2S(NL80211_CMD_PROBE_CLIENT)
+	C2S(NL80211_CMD_REGISTER_BEACONS)
+	C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+	C2S(NL80211_CMD_SET_NOACK_MAP)
+	C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+	C2S(NL80211_CMD_START_P2P_DEVICE)
+	C2S(NL80211_CMD_STOP_P2P_DEVICE)
+	C2S(NL80211_CMD_CONN_FAILED)
+	C2S(NL80211_CMD_SET_MCAST_RATE)
+	C2S(NL80211_CMD_SET_MAC_ACL)
+	C2S(NL80211_CMD_RADAR_DETECT)
+	C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+	C2S(NL80211_CMD_UPDATE_FT_IES)
+	C2S(NL80211_CMD_FT_EVENT)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+	default:
+		return "NL80211_CMD_UNKNOWN";
+	}
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_AP ||
@@ -369,13 +487,22 @@
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
 		nlmode == NL80211_IFTYPE_P2P_GO);
 }
 
 
+static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+	if (drv->associated)
+		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+	drv->associated = 0;
+	os_memset(drv->bssid, 0, ETH_ALEN);
+}
+
+
 struct nl80211_bss_info_arg {
 	struct wpa_driver_nl80211_data *drv;
 	struct wpa_scan_results *res;
@@ -480,6 +607,19 @@
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+	if (bss->wdev_id_set)
+		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+	else
+		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
 	struct family_data *res = arg;
@@ -546,6 +686,8 @@
 
 struct wiphy_idx_data {
 	int wiphy_idx;
+	enum nl80211_iftype nlmode;
+	u8 *macaddr;
 };
 
 
@@ -561,6 +703,13 @@
 	if (tb[NL80211_ATTR_WIPHY])
 		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
 
+	if (tb[NL80211_ATTR_IFTYPE])
+		info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+	if (tb[NL80211_ATTR_MAC] && info->macaddr)
+		os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+
 	return NL_SKIP;
 }
 
@@ -570,15 +719,17 @@
 	struct nl_msg *msg;
 	struct wiphy_idx_data data = {
 		.wiphy_idx = -1,
+		.macaddr = NULL,
 	};
 
 	msg = nlmsg_alloc();
 	if (!msg)
-		return -1;
+		return NL80211_IFTYPE_UNSPECIFIED;
 
 	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
 
 	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
 		return data.wiphy_idx;
@@ -589,6 +740,57 @@
 }
 
 
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.nlmode = NL80211_IFTYPE_UNSPECIFIED,
+		.macaddr = NULL,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
+	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+		return data.nlmode;
+	msg = NULL;
+nla_put_failure:
+	nlmsg_free(msg);
+	return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+#ifndef HOSTAPD
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.macaddr = bss->addr,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NL80211_IFTYPE_UNSPECIFIED;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
+	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return NL80211_IFTYPE_UNSPECIFIED;
+}
+#endif /* HOSTAPD */
+
+
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
 				    struct nl80211_wiphy_data *w)
 {
@@ -1053,6 +1255,7 @@
 	}
 
 	os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+	os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
 	os_memset(&event, 0, sizeof(event));
 	os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
 	event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
@@ -1132,6 +1335,7 @@
 
 	drv->associated = 1;
 	os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+	os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
 
 	os_memset(&event, 0, sizeof(event));
 	if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -1183,8 +1387,10 @@
 	}
 
 	drv->associated = 1;
-	if (addr)
+	if (addr) {
 		os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+	}
 
 	if (req_ie) {
 		event.assoc_info.req_ies = nla_data(req_ie);
@@ -1231,7 +1437,7 @@
 	}
 
 	wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 	os_memset(&data, 0, sizeof(data));
 	if (reason)
 		data.deauth_info.reason_code = nla_get_u16(reason);
@@ -1308,7 +1514,7 @@
 	u16 fc, stype;
 	int ssi_signal = 0;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Frame event");
+	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");
@@ -1400,6 +1606,22 @@
 	if (len >= 24) {
 		bssid = mgmt->bssid;
 
+		if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+		    !drv->associated &&
+		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+		    os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+		    os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+			/*
+			 * Avoid issues with some roaming cases where
+			 * disconnection event for the old AP may show up after
+			 * we have started connection with the new AP.
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+				   MAC2STR(bssid),
+				   MAC2STR(drv->auth_attempt_bssid));
+			return;
+		}
+
 		if (drv->associated != 0 &&
 		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
 		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
@@ -1415,7 +1637,7 @@
 		}
 	}
 
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 	os_memset(&event, 0, sizeof(event));
 
 	/* Note: Same offset for Reason Code in both frame subtypes */
@@ -1485,24 +1707,49 @@
 }
 
 
-static void mlme_event(struct wpa_driver_nl80211_data *drv,
+static void mlme_event(struct i802_bss *bss,
 		       enum nl80211_commands cmd, struct nlattr *frame,
 		       struct nlattr *addr, struct nlattr *timed_out,
 		       struct nlattr *freq, struct nlattr *ack,
 		       struct nlattr *cookie, struct nlattr *sig)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	const u8 *data;
+	size_t len;
+
 	if (timed_out && addr) {
 		mlme_timeout_event(drv, cmd, addr);
 		return;
 	}
 
 	if (frame == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-			   "data", cmd);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: MLME event %d (%s) without frame data",
+			   cmd, nl80211_command_to_string(cmd));
 		return;
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+	data = nla_data(frame);
+	len = nla_len(frame);
+	if (len < 4 + 2 * ETH_ALEN) {
+		wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+			   MACSTR ") - too short",
+			   cmd, nl80211_command_to_string(cmd), bss->ifname,
+			   MAC2STR(bss->addr));
+		return;
+	}
+	wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+		   ") A1=" MACSTR " A2=" MACSTR, cmd,
+		   nl80211_command_to_string(cmd), bss->ifname,
+		   MAC2STR(bss->addr), MAC2STR(data + 4),
+		   MAC2STR(data + 4 + ETH_ALEN));
+	if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+	    os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+	    os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+		wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+			   "for foreign address", bss->ifname);
+		return;
+	}
 	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
 		    nla_data(frame), nla_len(frame));
 
@@ -1728,6 +1975,7 @@
 	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
 	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
 		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+		[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
 	};
 	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
 	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1750,6 +1998,12 @@
 	sig_change->current_signal =
 		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+	if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+		sig_change->avg_signal =
+			(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+	else
+		sig_change->avg_signal = 0;
+
 	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
 		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
 				     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -2229,6 +2483,43 @@
 }
 
 
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+				struct nlattr **tb)
+{
+	union wpa_event_data data;
+	enum nl80211_radar_event event_type;
+
+	if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+		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]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+		   data.dfs_event.freq);
+
+	switch (event_type) {
+	case NL80211_RADAR_DETECTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+		break;
+	case NL80211_RADAR_CAC_FINISHED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+		break;
+	case NL80211_RADAR_CAC_ABORTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+		break;
+	case NL80211_RADAR_NOP_FINISHED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+			   "received", event_type);
+		break;
+	}
+}
+
+
 static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
 				   int wds)
 {
@@ -2252,6 +2543,9 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+		   cmd, nl80211_command_to_string(cmd), bss->ifname);
+
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
 	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
 	     cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2301,7 +2595,7 @@
 	case NL80211_CMD_FRAME_TX_STATUS:
 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
-		mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
+		mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
 			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
@@ -2373,6 +2667,9 @@
 	case NL80211_CMD_FT_EVENT:
 		mlme_event_ft_event(drv, tb);
 		break;
+	case NL80211_CMD_RADAR_DETECT:
+		nl80211_radar_event(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
@@ -2392,19 +2689,31 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
-	if (tb[NL80211_ATTR_IFINDEX])
+	if (tb[NL80211_ATTR_IFINDEX]) {
 		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-	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;
+		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;
+			}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+			   gnlh->cmd, ifidx);
+	} 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) {
+			if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+				do_process_drv_event(bss, gnlh->cmd, tb);
+				return NL_SKIP;
+			}
 		}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+			   gnlh->cmd, (long long unsigned int) wdev_id);
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-		   "interface (ifindex %d)", gnlh->cmd, ifidx);
-
 	return NL_SKIP;
 }
 
@@ -2417,17 +2726,26 @@
 	struct wpa_driver_nl80211_data *drv, *tmp;
 	int ifidx = -1;
 	struct i802_bss *bss;
+	u64 wdev_id = 0;
+	int wdev_id_set = 0;
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
 	if (tb[NL80211_ATTR_IFINDEX])
 		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+	else if (tb[NL80211_ATTR_WDEV]) {
+		wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		wdev_id_set = 1;
+	}
 
 	dl_list_for_each_safe(drv, tmp, &global->interfaces,
 			      struct wpa_driver_nl80211_data, list) {
 		for (bss = &drv->first_bss; bss; bss = bss->next) {
-			if (ifidx == -1 || ifidx == bss->ifindex) {
+			if ((ifidx == -1 && !wdev_id_set) ||
+			    ifidx == bss->ifindex ||
+			    (wdev_id_set && bss->wdev_id_set &&
+			     wdev_id == bss->wdev_id)) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
 			}
@@ -2447,10 +2765,14 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+		   gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+		   bss->ifname);
+
 	switch (gnlh->cmd) {
 	case NL80211_CMD_FRAME:
 	case NL80211_CMD_FRAME_TX_STATUS:
-		mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+		mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
 			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
@@ -2477,7 +2799,7 @@
 {
 	struct nl_cb *cb = eloop_ctx;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
 
 	nl_recvmsgs(handle, cb);
 }
@@ -2607,6 +2929,10 @@
 		case NL80211_IFTYPE_ADHOC:
 			info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
 			break;
+		case NL80211_IFTYPE_P2P_DEVICE:
+			info->capa->flags |=
+				WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+			break;
 		case NL80211_IFTYPE_P2P_GO:
 			info->p2p_go_supported = 1;
 			break;
@@ -2635,6 +2961,7 @@
 		[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
 		[NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
 		[NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+		[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
 	},
 	iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
 		[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
@@ -2648,6 +2975,9 @@
 	    !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
 		return 0; /* broken combination */
 
+	if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+		info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
 	nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
 			    rem_limit) {
 		err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
@@ -2727,9 +3057,6 @@
 static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
 			       struct nlattr *tb)
 {
-	/* default to 5000 since early versions of mac80211 don't set it */
-	capa->max_remain_on_chan = 5000;
-
 	if (tb)
 		capa->max_remain_on_chan = nla_get_u32(tb);
 }
@@ -2803,6 +3130,10 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	if (tb[NL80211_ATTR_WIPHY_NAME])
+		os_strncpy(drv->phyname,
+			   nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+			   sizeof(drv->phyname));
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
 		capa->max_scan_ssids =
 			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
@@ -2815,6 +3146,10 @@
 		capa->max_match_sets =
 			nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
 
+	if (tb[NL80211_ATTR_MAC_ACL_MAX])
+		capa->max_acl_mac_addrs =
+			nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
 	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]);
@@ -2895,7 +3230,8 @@
 		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->first_bss.ifindex);
+	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))
 		return -1;
@@ -2921,6 +3257,11 @@
 			   "concurrent (driver advertised support)");
 		drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
 	}
+
+	/* default to 5000 since early versions of mac80211 don't set it */
+	if (!drv->capa.max_remain_on_chan)
+		drv->capa.max_remain_on_chan = 5000;
+
 	return 0;
 nla_put_failure:
 	nlmsg_free(msg);
@@ -3163,39 +3504,6 @@
 }
 
 
-static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
-{
-	/* Find phy (radio) to which this interface belongs */
-	char buf[90], *pos;
-	int f, rv;
-
-	drv->phyname[0] = '\0';
-	snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
-		 drv->first_bss.ifname);
-	f = open(buf, O_RDONLY);
-	if (f < 0) {
-		wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
-			   buf, strerror(errno));
-		return;
-	}
-
-	rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
-	close(f);
-	if (rv < 0) {
-		wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
-			   buf, strerror(errno));
-		return;
-	}
-
-	drv->phyname[rv] = '\0';
-	pos = os_strchr(drv->phyname, '\n');
-	if (pos)
-		*pos = '\0';
-	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
-		   drv->first_bss.ifname, drv->phyname);
-}
-
-
 static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
 						      void *eloop_ctx,
 						      void *handle)
@@ -3317,8 +3625,6 @@
 	if (nl80211_init_bss(bss))
 		goto failed;
 
-	nl80211_get_phy_name(drv);
-
 	rcfg = os_zalloc(sizeof(*rcfg));
 	if (rcfg == NULL)
 		goto failed;
@@ -3389,7 +3695,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
 	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3626,27 +3934,124 @@
 }
 
 
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+		   bss->ifname, (long long unsigned int) bss->wdev_id,
+		   strerror(ret));
+
+nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	if (start)
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+	else
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+
+	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));
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+	enum nl80211_iftype nlmode;
+
+	nlmode = nl80211_get_ifmode(bss);
+	if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+		return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+					     bss->ifname, up);
+	}
+
+	/* P2P Device has start/stop which is equivalent */
+	return nl80211_set_p2pdev(bss, up);
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
+#ifndef HOSTAPD
+	enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
+#endif /* HOSTAPD */
 	struct i802_bss *bss = &drv->first_bss;
 	int send_rfkill_event = 0;
+	int dynamic_if;
 
 	drv->ifindex = if_nametoindex(bss->ifname);
-	drv->first_bss.ifindex = drv->ifindex;
+	bss->ifindex = drv->ifindex;
+	bss->wdev_id = drv->global->if_add_wdevid;
+	bss->wdev_id_set = drv->global->if_add_wdevid_set;
+
+	dynamic_if = drv->ifindex == drv->global->if_add_ifindex;
+	dynamic_if = dynamic_if || drv->global->if_add_wdevid_set;
+	drv->global->if_add_wdevid_set = 0;
+
+	if (wpa_driver_nl80211_capa(drv))
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+		   bss->ifname, drv->phyname);
 
 #ifndef HOSTAPD
+	if (dynamic_if)
+		nlmode = nl80211_get_ifmode(bss);
+
 	/*
 	 * 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 (drv->ifindex != drv->global->if_add_ifindex &&
-	    wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
-			   "use managed mode");
+	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
 		return -1;
 	}
+	drv->nlmode = nlmode;
+
+	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+		int ret = nl80211_set_p2pdev(bss, 1);
+		if (ret < 0)
+			wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+		nl80211_get_macaddr(bss);
+		return ret;
+	}
 
 	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		if (rfkill_is_blocked(drv->rfkill)) {
@@ -3666,9 +4071,6 @@
 			       1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
-	if (wpa_driver_nl80211_capa(drv))
-		return -1;
-
 	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 			       bss->addr))
 		return -1;
@@ -3765,10 +4167,13 @@
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
-	wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
-	nl80211_mgmt_unsubscribe(bss, "deinit");
-
+	(void) i802_set_iface_flags(bss, 0);
+	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+		wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+	} else {
+		nl80211_mgmt_unsubscribe(bss, "deinit");
+		nl80211_del_p2pdev(bss);
+	}
 	nl_cb_put(drv->nl_cb);
 
 	nl80211_destroy_bss(&drv->first_bss);
@@ -3809,10 +4214,9 @@
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-		    struct wpa_driver_scan_params *params)
+		    struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
 	struct nl_msg *msg;
-	int err;
 	size_t i;
 
 	msg = nlmsg_alloc();
@@ -3821,27 +4225,26 @@
 
 	nl80211_cmd(drv, msg, 0, cmd);
 
-	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-		goto fail;
+	if (!wdev_id)
+		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	else
+		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
 
 	if (params->num_ssids) {
-		struct nl_msg *ssids = nlmsg_alloc();
+		struct nlattr *ssids;
+
+		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
 		if (ssids == NULL)
 			goto fail;
 		for (i = 0; i < params->num_ssids; i++) {
 			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
 					  params->ssids[i].ssid,
 					  params->ssids[i].ssid_len);
-			if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
-				    params->ssids[i].ssid) < 0) {
-				nlmsg_free(ssids);
+			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+				    params->ssids[i].ssid) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-		nlmsg_free(ssids);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, ssids);
 	}
 
 	if (params->extra_ies) {
@@ -3853,22 +4256,17 @@
 	}
 
 	if (params->freqs) {
-		struct nl_msg *freqs = nlmsg_alloc();
+		struct nlattr *freqs;
+		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
 		if (freqs == NULL)
 			goto fail;
 		for (i = 0; params->freqs[i]; i++) {
 			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
 				   "MHz", params->freqs[i]);
-			if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
-				nlmsg_free(freqs);
+			if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
-				     freqs);
-		nlmsg_free(freqs);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, freqs);
 	}
 
 	os_free(drv->filter_ssids);
@@ -3879,6 +4277,7 @@
 	return msg;
 
 fail:
+nla_put_failure:
 	nlmsg_free(msg);
 	return NULL;
 }
@@ -3895,19 +4294,22 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1, timeout;
-	struct nl_msg *msg, *rates = NULL;
+	struct nl_msg *msg = NULL;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
 	drv->scan_for_auth = 0;
 
-	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+				  bss->wdev_id_set ? &bss->wdev_id : NULL);
 	if (!msg)
 		return -1;
 
 	if (params->p2p_probe) {
+		struct nlattr *rates;
+
 		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
-		rates = nlmsg_alloc();
+		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
 		if (rates == NULL)
 			goto nla_put_failure;
 
@@ -3917,11 +4319,9 @@
 		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
 		 * rates are left enabled.
 		 */
-		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+		NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
 			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-		if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
-		    0)
-			goto nla_put_failure;
+		nla_nest_end(msg, rates);
 
 		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
 	}
@@ -3975,7 +4375,6 @@
 
 nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(rates);
 	return ret;
 }
 
@@ -3995,8 +4394,6 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
 	struct nl_msg *msg;
-	struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
-	struct nl_msg *match_set_rssi = NULL;
 	size_t i;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
@@ -4006,7 +4403,8 @@
 		return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+				  bss->wdev_id_set ? &bss->wdev_id : NULL);
 	if (!msg)
 		goto nla_put_failure;
 
@@ -4015,46 +4413,42 @@
 	if ((drv->num_filter_ssids &&
 	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
 	    params->filter_rssi) {
-		match_sets = nlmsg_alloc();
+		struct nlattr *match_sets;
+		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
 		if (match_sets == NULL)
 			goto nla_put_failure;
 
 		for (i = 0; i < drv->num_filter_ssids; i++) {
+			struct nlattr *match_set_ssid;
 			wpa_hexdump_ascii(MSG_MSGDUMP,
 					  "nl80211: Sched scan filter SSID",
 					  drv->filter_ssids[i].ssid,
 					  drv->filter_ssids[i].ssid_len);
 
-			match_set_ssid = nlmsg_alloc();
+			match_set_ssid = nla_nest_start(msg, i + 1);
 			if (match_set_ssid == NULL)
 				goto nla_put_failure;
-			NLA_PUT(match_set_ssid,
-				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
 
-			if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
-			    0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_set_ssid);
 		}
 
 		if (params->filter_rssi) {
-			match_set_rssi = nlmsg_alloc();
+			struct nlattr *match_set_rssi;
+			match_set_rssi = nla_nest_start(msg, 0);
 			if (match_set_rssi == NULL)
 				goto nla_put_failure;
-			NLA_PUT_U32(match_set_rssi,
-				    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+			NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 				    params->filter_rssi);
 			wpa_printf(MSG_MSGDUMP,
 				   "nl80211: Sched scan RSSI filter %d dBm",
 				   params->filter_rssi);
-			if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_set_rssi);
 		}
 
-		if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-				   match_sets) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, match_sets);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4072,9 +4466,6 @@
 		   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-	nlmsg_free(match_set_ssid);
-	nlmsg_free(match_sets);
-	nlmsg_free(match_set_rssi);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -4416,7 +4807,8 @@
 		goto nla_put_failure;
 
 	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 
 	arg.drv = drv;
 	arg.res = res;
@@ -4487,13 +4879,18 @@
 				      const u8 *key, size_t key_len)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ifindex = if_nametoindex(ifname);
+	int ifindex;
 	struct nl_msg *msg;
 	int ret;
 
-	wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+	/* Ignore for P2P Device */
+	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+		return 0;
+
+	ifindex = if_nametoindex(ifname);
+	wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
 		   "set_tx=%d seq_len=%lu key_len=%lu",
-		   __func__, ifindex, alg, addr, key_idx, set_tx,
+		   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
 		   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
 	if (key_idx == -1)
@@ -4563,18 +4960,15 @@
 				    NL80211_KEYTYPE_GROUP);
 		}
 	} else if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
+		struct nlattr *types;
+
 		wpa_printf(MSG_DEBUG, "   broadcast key");
-		types = nlmsg_alloc();
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	}
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4608,29 +5002,21 @@
 	else
 		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
 	if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	} else if (addr) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+		nla_nest_end(msg, types);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4804,7 +5190,7 @@
 					 int reason_code)
 {
 	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 	drv->ignore_next_local_disconnect = 0;
 	/* Disconnect command doesn't need BSSID - it uses cached value */
 	return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
@@ -4820,7 +5206,7 @@
 		return wpa_driver_nl80211_disconnect(drv, reason_code);
 	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
 		   __func__, MAC2STR(addr), reason_code);
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 	if (drv->nlmode == NL80211_IFTYPE_ADHOC)
 		return nl80211_leave_ibss(drv);
 	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
@@ -4888,8 +5274,12 @@
 	is_retry = drv->retry_auth;
 	drv->retry_auth = 0;
 
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 	os_memset(drv->auth_bssid, 0, ETH_ALEN);
+	if (params->bssid)
+		os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+	else
+		os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
 	/* FIX: IBSS mode */
 	nlmode = params->p2p ?
 		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
@@ -5131,35 +5521,11 @@
 			  struct hostapd_channel_data *chan,
 			  struct nlattr *tb_freq[])
 {
-	enum hostapd_hw_mode m;
-
+	u8 channel;
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
 	chan->flag = 0;
-
-	if (chan->freq < 4000)
-		m = HOSTAPD_MODE_IEEE80211B;
-	else if (chan->freq > 50000)
-		m = HOSTAPD_MODE_IEEE80211AD;
-	else
-		m = HOSTAPD_MODE_IEEE80211A;
-
-	switch (m) {
-	case HOSTAPD_MODE_IEEE80211AD:
-		chan->chan = (chan->freq - 56160) / 2160;
-		break;
-	case HOSTAPD_MODE_IEEE80211A:
-		chan->chan = chan->freq / 5 - 1000;
-		break;
-	case HOSTAPD_MODE_IEEE80211B:
-	case HOSTAPD_MODE_IEEE80211G:
-		if (chan->freq == 2484)
-			chan->chan = 14;
-		else
-			chan->chan = (chan->freq - 2407) / 5;
-		break;
-	default:
-		break;
-	}
+	if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+		chan->chan = channel;
 
 	if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
 		chan->flag |= HOSTAPD_CHAN_DISABLED;
@@ -5174,6 +5540,22 @@
 	    !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]);
+
+		switch (state) {
+		case NL80211_DFS_USABLE:
+			chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+			break;
+		case NL80211_DFS_AVAILABLE:
+			chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+			break;
+		case NL80211_DFS_UNAVAILABLE:
+			chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+			break;
+		}
+	}
 }
 
 
@@ -5187,6 +5569,7 @@
 		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .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 },
 	};
 	int new_channels = 0;
 	struct hostapd_channel_data *channel;
@@ -5716,7 +6099,8 @@
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
 
-	if (is_sta_interface(drv->nlmode) &&
+	if ((is_sta_interface(drv->nlmode) ||
+	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
 	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
 		/*
@@ -5807,6 +6191,60 @@
 }
 
 
+static int wpa_driver_nl80211_set_acl(void *priv,
+				      struct hostapd_acl_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *acl;
+	unsigned int i;
+	int ret = 0;
+
+	if (!(drv->capa.max_acl_mac_addrs))
+		return -ENOTSUP;
+
+	if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+		return -ENOTSUP;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+		   params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+		    NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+		    NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+	acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+	if (acl == NULL)
+		goto nla_put_failure;
+
+	for (i = 0; i < params->num_mac_acl; i++)
+		NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+	nla_nest_end(msg, acl);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+			   ret, strerror(-ret));
+	}
+
+nla_put_failure:
+	nlmsg_free(msg);
+
+	return ret;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
 				     struct wpa_driver_ap_params *params)
 {
@@ -6102,7 +6540,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *wme = NULL;
+	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
 	int ret = -ENOBUFS;
 
@@ -6126,12 +6564,25 @@
 	wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
 		    params->supp_rates_len);
 	if (!params->set) {
-		wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
-		NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		if (params->aid) {
+			wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
+			NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		} else {
+			/*
+			 * cfg80211 validates that AID is non-zero, so we have
+			 * to make this a non-zero value for the TDLS case where
+			 * a dummy STA entry is used for now.
+			 */
+			wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
+			NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+		}
 		wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
 			   params->listen_interval);
 		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
 			    params->listen_interval);
+	} else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+		wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
+		NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
 	}
 	if (params->ht_capabilities) {
 		wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
@@ -6169,18 +6620,18 @@
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
 	if (params->flags & WPA_STA_WMM) {
-		wme = nlmsg_alloc();
+		struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
 		if (!wme)
 			goto nla_put_failure;
 
 		wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
-		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+		NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
 				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+		NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
 				(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
 				WMM_QOSINFO_STA_SP_MASK);
-		if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, wme);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6192,7 +6643,6 @@
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
-	nlmsg_free(wme);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -6259,12 +6709,20 @@
 		return "STATION";
 	case NL80211_IFTYPE_AP:
 		return "AP";
+	case NL80211_IFTYPE_AP_VLAN:
+		return "AP_VLAN";
+	case NL80211_IFTYPE_WDS:
+		return "WDS";
 	case NL80211_IFTYPE_MONITOR:
 		return "MONITOR";
+	case NL80211_IFTYPE_MESH_POINT:
+		return "MESH_POINT";
 	case NL80211_IFTYPE_P2P_CLIENT:
 		return "P2P_CLIENT";
 	case NL80211_IFTYPE_P2P_GO:
 		return "P2P_GO";
+	case NL80211_IFTYPE_P2P_DEVICE:
+		return "P2P_DEVICE";
 	default:
 		return "unknown";
 	}
@@ -6274,9 +6732,11 @@
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 				     const char *ifname,
 				     enum nl80211_iftype iftype,
-				     const u8 *addr, int wds)
+				     const u8 *addr, int wds,
+				     int (*handler)(struct nl_msg *, void *),
+				     void *arg)
 {
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
 	int ifidx;
 	int ret = -ENOBUFS;
 
@@ -6288,30 +6748,26 @@
 		return -1;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	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);
 
 	if (iftype == NL80211_IFTYPE_MONITOR) {
-		int err;
+		struct nlattr *flags;
 
-		flags = nlmsg_alloc();
+		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
 		if (!flags)
 			goto nla_put_failure;
 
-		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+		NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-		nlmsg_free(flags);
-
-		if (err)
-			goto nla_put_failure;
+		nla_nest_end(msg, flags);
 	} else if (wds) {
 		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, handler, arg);
 	msg = NULL;
 	if (ret) {
  nla_put_failure:
@@ -6321,6 +6777,9 @@
 		return ret;
 	}
 
+	if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+		return 0;
+
 	ifidx = if_nametoindex(ifname);
 	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
 		   ifname, ifidx);
@@ -6343,11 +6802,14 @@
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 				const char *ifname, enum nl80211_iftype iftype,
-				const u8 *addr, int wds)
+				const u8 *addr, int wds,
+				int (*handler)(struct nl_msg *, void *),
+				void *arg)
 {
 	int ret;
 
-	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+					arg);
 
 	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -6358,10 +6820,10 @@
 
 		/* Try to create the interface again */
 		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-						wds);
+						wds, handler, arg);
 	}
 
-	if (ret >= 0 && is_p2p_interface(iftype))
+	if (ret >= 0 && is_p2p_net_interface(iftype))
 		nl80211_disable_11b_rates(drv, ret, 1);
 
 	return ret;
@@ -6708,7 +7170,7 @@
 
 	drv->monitor_ifidx =
 		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0);
+				     0, NULL, NULL);
 
 	if (drv->monitor_ifidx == -EOPNOTSUPP) {
 		/*
@@ -6939,19 +7401,14 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
+	struct nlattr *flags;
 	struct nl80211_sta_flag_update upd;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	flags = nlmsg_alloc();
-	if (!flags) {
-		nlmsg_free(msg);
-		return -ENOMEM;
-	}
-
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6962,35 +7419,34 @@
 	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
 	 * can be removed eventually.
 	 */
+	flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+	if (!flags)
+		goto nla_put_failure;
 	if (total_flags & WPA_STA_AUTHORIZED)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
 	if (total_flags & WPA_STA_WMM)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
 	if (total_flags & WPA_STA_SHORT_PREAMBLE)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
 	if (total_flags & WPA_STA_MFP)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
 	if (total_flags & WPA_STA_TDLS_PEER)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-		goto nla_put_failure;
+	nla_nest_end(msg, flags);
 
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
 	upd.set = sta_flags_nl80211(flags_or);
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
-	nlmsg_free(flags);
-
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(flags);
 	return -ENOBUFS;
 }
 
@@ -7410,7 +7866,7 @@
 		return wpa_driver_nl80211_connect(drv, params);
 	}
 
-	drv->associated = 0;
+	nl80211_mark_disconnected(drv);
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -7577,7 +8033,8 @@
 		return -ENOMEM;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7602,6 +8059,9 @@
 	int res;
 
 	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+	if (res && nlmode == nl80211_get_ifmode(bss))
+		res = 0;
+
 	if (res == 0) {
 		drv->nlmode = nlmode;
 		ret = 0;
@@ -7625,8 +8085,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
 		   "interface down");
 	for (i = 0; i < 10; i++) {
-		res = linux_set_iface_flags(drv->global->ioctl_sock,
-					    bss->ifname, 0);
+		res = i802_set_iface_flags(bss, 0);
 		if (res == -EACCES || res == -ENODEV)
 			break;
 		if (res == 0) {
@@ -7635,8 +8094,7 @@
 			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
 			if (ret == -EACCES)
 				break;
-			res = linux_set_iface_flags(drv->global->ioctl_sock,
-						    bss->ifname, 1);
+			res = i802_set_iface_flags(bss, 1);
 			if (res && !ret)
 				ret = -1;
 			else if (ret != -EBUSY)
@@ -7661,7 +8119,7 @@
 		return ret;
 	}
 
-	if (is_p2p_interface(nlmode))
+	if (is_p2p_net_interface(nlmode))
 		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
 	else if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -7700,6 +8158,13 @@
 		capa->extended_capa_mask = drv->extended_capa_mask;
 		capa->extended_capa_len = drv->extended_capa_len;
 	}
+
+	if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+	    !drv->allow_p2p_device) {
+		wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+		capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+	}
+
 	return 0;
 }
 
@@ -7724,6 +8189,9 @@
 	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+		   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
@@ -8235,7 +8703,7 @@
 		if (!if_nametoindex(name)) {
 			if (nl80211_create_iface(drv, name,
 						 NL80211_IFTYPE_AP_VLAN,
-						 bss->addr, 1) < 0)
+						 bss->addr, 1, NULL, NULL) < 0)
 				return -1;
 			if (bridge_ifname &&
 			    linux_br_add_if(drv->global->ioctl_sock,
@@ -8451,6 +8919,8 @@
 		return NL80211_IFTYPE_AP;
 	case WPA_IF_P2P_GO:
 		return NL80211_IFTYPE_P2P_GO;
+	case WPA_IF_P2P_DEVICE:
+		return NL80211_IFTYPE_P2P_DEVICE;
 	}
 	return -1;
 }
@@ -8497,12 +8967,40 @@
 #endif /* CONFIG_P2P */
 
 
+struct wdev_info {
+	u64 wdev_id;
+	int wdev_id_set;
+	u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct wdev_info *wi = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (tb[NL80211_ATTR_WDEV]) {
+		wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		wi->wdev_id_set = 1;
+	}
+
+	if (tb[NL80211_ATTR_MAC])
+		os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+
+	return NL_SKIP;
+}
+
+
 static int wpa_driver_nl80211_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)
 {
+	enum nl80211_iftype nlmode;
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifidx;
@@ -8518,21 +9016,46 @@
 
 	if (addr)
 		os_memcpy(if_addr, addr, ETH_ALEN);
-	ifidx = nl80211_create_iface(drv, ifname,
-				     wpa_driver_nl80211_if_type(type), addr,
-				     0);
-	if (ifidx < 0) {
+	nlmode = wpa_driver_nl80211_if_type(type);
+	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+		struct wdev_info p2pdev_info;
+
+		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+					     0, nl80211_wdev_handler,
+					     &p2pdev_info);
+		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+				   ifname);
+			return -1;
+		}
+
+		drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+		drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+		if (!is_zero_ether_addr(p2pdev_info.macaddr))
+			os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+		wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+			   ifname,
+			   (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);
+			os_free(new_bss);
 #endif /* HOSTAPD */
-		return -1;
+			return -1;
+		}
 	}
 
-	if (!addr &&
-	    linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-			       if_addr) < 0) {
-		nl80211_remove_iface(drv, ifidx);
-		return -1;
+	if (!addr) {
+		if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+			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);
+			return -1;
+		}
 	}
 
 #ifdef CONFIG_P2P
@@ -8540,16 +9063,14 @@
 	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
 	     type == WPA_IF_P2P_GO)) {
 		/* Enforce unique P2P Interface Address */
-		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+		u8 new_addr[ETH_ALEN];
 
-		if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-				       own_addr) < 0 ||
-		    linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+		if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
 				       new_addr) < 0) {
 			nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
-		if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+		if (nl80211_addr_in_use(drv->global, new_addr)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
 				   "for P2P group interface");
 			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
@@ -8692,12 +9213,14 @@
 	if (!msg)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+	wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
 		   "no_ack=%d offchanok=%d",
 		   freq, wait, no_cck, no_ack, offchanok);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 	if (wait)
 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -8719,7 +9242,7 @@
 			   freq, wait);
 		goto nla_put_failure;
 	}
-	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+	wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
 		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
 		   (long long unsigned int) cookie);
 
@@ -8790,7 +9313,8 @@
 		   (long long unsigned int) drv->send_action_cookie);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8819,7 +9343,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -8866,7 +9392,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8996,6 +9524,18 @@
 }
 
 
+static int wpa_driver_nl80211_stop_ap(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!is_ap_interface(drv->nlmode))
+		return -1;
+	wpa_driver_nl80211_del_beacon(drv);
+	bss->beacon_set = 0;
+	return 0;
+}
+
+
 static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 {
 	struct i802_bss *bss = priv;
@@ -9009,11 +9549,9 @@
 static void wpa_driver_nl80211_resume(void *priv)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
-			   "resume event");
-	}
+
+	if (i802_set_iface_flags(bss, 1))
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
 }
 
 
@@ -9068,7 +9606,8 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *cqm = NULL;
+	struct nl_msg *msg;
+	struct nlattr *cqm;
 	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
@@ -9082,25 +9621,92 @@
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-	cqm = nlmsg_alloc();
+	cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
 	if (cqm == NULL)
 		goto nla_put_failure;
 
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-	if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
-		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+	nla_nest_end(msg, cqm);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 
 nla_put_failure:
-	nlmsg_free(cqm);
 	nlmsg_free(msg);
 	return ret;
 }
 
 
+/* 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];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wpa_signal_info *sig_change = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	sig_change->center_frq1 = -1;
+	sig_change->center_frq2 = -1;
+	sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+		sig_change->chanwidth = convert2width(
+			nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+		if (tb[NL80211_ATTR_CENTER_FREQ1])
+			sig_change->center_frq1 =
+				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+		if (tb[NL80211_ATTR_CENTER_FREQ2])
+			sig_change->center_frq2 =
+				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+				     struct wpa_signal_info *sig)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
 static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 {
 	struct i802_bss *bss = priv;
@@ -9112,6 +9718,10 @@
 	if (res != 0)
 		return res;
 
+	res = nl80211_get_channel_width(drv, si);
+	if (res != 0)
+		return res;
+
 	return nl80211_get_link_noise(drv, si);
 }
 
@@ -9186,6 +9796,13 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
 	}
+
+	if (os_strstr(param, "p2p_device=1")) {
+		struct i802_bss *bss = priv;
+		struct wpa_driver_nl80211_data *drv = bss->drv;
+		drv->allow_p2p_device = 1;
+	}
+
 #ifdef ANDROID_P2P
 	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
 		struct i802_bss *bss = priv;
@@ -9474,6 +10091,40 @@
 }
 
 
+static int nl80211_start_radar_detection(void *priv, int 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)");
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+			   "detection");
+		return -1;
+	}
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	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);
+
+	/* only HT20 is supported at this point */
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret == 0)
+		return 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+		   "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+	return -1;
+}
+
 #ifdef CONFIG_TDLS
 
 static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -9835,6 +10486,18 @@
 }
 
 
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+		return NULL;
+
+	return bss->addr;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -9857,6 +10520,7 @@
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
 	.set_ap = wpa_driver_nl80211_set_ap,
+	.set_acl = wpa_driver_nl80211_set_acl,
 	.if_add = wpa_driver_nl80211_if_add,
 	.if_remove = driver_nl80211_if_remove,
 	.send_mlme = driver_nl80211_send_mlme,
@@ -9906,11 +10570,14 @@
 	.set_rekey_info = nl80211_set_rekey_info,
 	.poll_client = nl80211_poll_client,
 	.set_p2p_powersave = nl80211_set_p2p_powersave,
+	.start_dfs_cac = nl80211_start_radar_detection,
+	.stop_ap = wpa_driver_nl80211_stop_ap,
 #ifdef CONFIG_TDLS
 	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
 	.tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
 #ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
 	.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index c99802a..541ebcc 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -3195,6 +3195,12 @@
 	/* TODO */
 }
 
+
+static void test_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+	wpa_printf(level, "P2P: %s", msg);
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -3206,8 +3212,8 @@
 	int i;
 
 	os_memset(&p2p, 0, sizeof(p2p));
-	p2p.msg_ctx = drv->ctx;
 	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;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 9733e01..1401050 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -502,11 +502,9 @@
 					   "IWEVCUSTOM length");
 				return;
 			}
-			buf = os_malloc(iwe->u.data.length + 1);
+			buf = dup_binstr(custom, iwe->u.data.length);
 			if (buf == NULL)
 				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
 			wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
 			os_free(buf);
 			break;
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index 1d0ff6e..04eb4fd 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -50,12 +50,12 @@
 
 struct wpa_driver_ops *wpa_drivers[] =
 {
-#ifdef CONFIG_DRIVER_WEXT
-	&wpa_driver_wext_ops,
-#endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_NL80211
 	&wpa_driver_nl80211_ops,
 #endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_WEXT
+	&wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_HOSTAP
 	&wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 79da871..32b060e 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -27,6 +27,8 @@
 
 #include <linux/types.h>
 
+#define NL80211_GENL_NAME "nl80211"
+
 /**
  * DOC: Station handling
  *
@@ -639,6 +641,13 @@
  *	with the relevant Information Elements. This event is used to report
  *	received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
  *
+ * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running
+ *	a critical protocol that needs more reliability in the connection to
+ *	complete.
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
+ *	return back to normal.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -798,6 +807,9 @@
 	NL80211_CMD_UPDATE_FT_IES,
 	NL80211_CMD_FT_EVENT,
 
+	NL80211_CMD_CRIT_PROTOCOL_START,
+	NL80211_CMD_CRIT_PROTOCOL_STOP,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1414,6 +1426,16 @@
  * @NL80211_ATTR_IE_RIC: Resource Information Container Information
  *	Element
  *
+ * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased
+ *	reliability, see &enum nl80211_crit_proto_id (u16).
+ * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which
+ *      the connection should have increased reliability (u16).
+ *
+ * @NL80211_ATTR_PEER_AID: Association ID for the peer TDLS station (u16).
+ *	This is similar to @NL80211_ATTR_STA_AID but with a difference of being
+ *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
+ *	update a TDLS peer STA entry.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1709,6 +1731,11 @@
 	NL80211_ATTR_MDID,
 	NL80211_ATTR_IE_RIC,
 
+	NL80211_ATTR_CRIT_PROT_ID,
+	NL80211_ATTR_MAX_CRIT_PROT_DURATION,
+
+	NL80211_ATTR_PEER_AID,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1973,6 +2000,10 @@
  * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
  * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
  *	non-peer STA
+ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
+ *	Contains a nested array of signal strength attributes (u8, dBm)
+ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
+ *	Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2002,6 +2033,8 @@
 	NL80211_STA_INFO_NONPEER_PM,
 	NL80211_STA_INFO_RX_BYTES64,
 	NL80211_STA_INFO_TX_BYTES64,
+	NL80211_STA_INFO_CHAIN_SIGNAL,
+	NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -2619,6 +2652,10 @@
  * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
  *	implement an MPM which handles peer allocation and state.
  *
+ * @NL80211_MESH_SETUP_AUTH_PROTOCOL: Inform the kernel of the authentication
+ *	method (u8, as defined in IEEE 8.4.2.100.6, e.g. 0x1 for SAE).
+ *	Default is no authentication method required.
+ *
  * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2632,6 +2669,7 @@
 	NL80211_MESH_SETUP_USERSPACE_AMPE,
 	NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
 	NL80211_MESH_SETUP_USERSPACE_MPM,
+	NL80211_MESH_SETUP_AUTH_PROTOCOL,
 
 	/* keep last */
 	__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -3682,4 +3720,25 @@
 	NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP =	1 << 0,
 };
 
+/**
+ * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers
+ *
+ * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified.
+ * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol.
+ * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol.
+ * @NL80211_CRIT_PROTO_APIPA: APIPA protocol.
+ * @NUM_NL80211_CRIT_PROTO: must be kept last.
+ */
+enum nl80211_crit_proto_id {
+	NL80211_CRIT_PROTO_UNSPEC,
+	NL80211_CRIT_PROTO_DHCP,
+	NL80211_CRIT_PROTO_EAPOL,
+	NL80211_CRIT_PROTO_APIPA,
+	/* add other protocols before this one */
+	NUM_NL80211_CRIT_PROTO
+};
+
+/* maximum duration for critical protocol measures */
+#define NL80211_CRIT_PROTO_MAX_DURATION		5000 /* msec */
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 0d247c4..f5890be 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -63,6 +63,7 @@
 	EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
 	EAP_TYPE_GPSK = 51 /* RFC 5433 */,
 	EAP_TYPE_PWD = 52 /* RFC 5931 */,
+	EAP_TYPE_EKE = 53 /* RFC 6124 */,
 	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 } EapType;
 
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
new file mode 100644
index 0000000..a62ac8e
--- /dev/null
+++ b/src/eap_common/eap_eke_common.c
@@ -0,0 +1,768 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eap_common/eap_defs.h"
+#include "eap_eke_common.h"
+
+
+static int eap_eke_dh_len(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return 128;
+	case EAP_EKE_DHGROUP_EKE_5:
+		return 192;
+	case EAP_EKE_DHGROUP_EKE_14:
+		return 256;
+	case EAP_EKE_DHGROUP_EKE_15:
+		return 384;
+	case EAP_EKE_DHGROUP_EKE_16:
+		return 512;
+	}
+
+	return -1;
+}
+
+
+static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
+{
+	int dhlen;
+
+	dhlen = eap_eke_dh_len(dhgroup);
+	if (dhlen < 0)
+		return -1;
+	if (encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+	return AES_BLOCK_SIZE + dhlen;
+}
+
+
+static const struct dh_group * eap_eke_dh_group(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return dh_groups_get(2);
+	case EAP_EKE_DHGROUP_EKE_5:
+		return dh_groups_get(5);
+	case EAP_EKE_DHGROUP_EKE_14:
+		return dh_groups_get(14);
+	case EAP_EKE_DHGROUP_EKE_15:
+		return dh_groups_get(15);
+	case EAP_EKE_DHGROUP_EKE_16:
+		return dh_groups_get(16);
+	}
+
+	return NULL;
+}
+
+
+static int eap_eke_dh_generator(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return 5;
+	case EAP_EKE_DHGROUP_EKE_5:
+		return 31;
+	case EAP_EKE_DHGROUP_EKE_14:
+		return 11;
+	case EAP_EKE_DHGROUP_EKE_15:
+		return 5;
+	case EAP_EKE_DHGROUP_EKE_16:
+		return 5;
+	}
+
+	return -1;
+}
+
+
+static int eap_eke_pnonce_len(u8 mac)
+{
+	int mac_len;
+
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		mac_len = SHA1_MAC_LEN;
+	else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		mac_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	return AES_BLOCK_SIZE + 16 + mac_len;
+}
+
+
+static int eap_eke_pnonce_ps_len(u8 mac)
+{
+	int mac_len;
+
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		mac_len = SHA1_MAC_LEN;
+	else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		mac_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	return AES_BLOCK_SIZE + 2 * 16 + mac_len;
+}
+
+
+static int eap_eke_prf_len(u8 prf)
+{
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return 20;
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return 32;
+	return -1;
+}
+
+
+static int eap_eke_nonce_len(u8 prf)
+{
+	int prf_len;
+
+	prf_len = eap_eke_prf_len(prf);
+	if (prf_len < 0)
+		return -1;
+
+	if (prf_len > 2 * 16)
+		return (prf_len + 1) / 2;
+
+	return 16;
+}
+
+
+static int eap_eke_auth_len(u8 prf)
+{
+	switch (prf) {
+	case EAP_EKE_PRF_HMAC_SHA1:
+		return SHA1_MAC_LEN;
+	case EAP_EKE_PRF_HMAC_SHA2_256:
+		return SHA256_MAC_LEN;
+	}
+
+	return -1;
+}
+
+
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
+{
+	int generator;
+	u8 gen;
+	const struct dh_group *dh;
+	size_t pub_len, i;
+
+	generator = eap_eke_dh_generator(group);
+	if (generator < 0 || generator > 255)
+		return -1;
+	gen = generator;
+
+	dh = eap_eke_dh_group(group);
+	if (dh == NULL)
+		return -1;
+
+	/* x = random number 2 .. p-1 */
+	if (random_get_bytes(ret_priv, dh->prime_len))
+		return -1;
+	if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		ret_priv[0] = 0;
+	}
+	for (i = 0; i < dh->prime_len - 1; i++) {
+		if (ret_priv[i])
+			break;
+	}
+	if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
+			ret_priv, dh->prime_len);
+
+	/* y = g ^ x (mod p) */
+	pub_len = dh->prime_len;
+	if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
+			   dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
+		return -1;
+	if (pub_len < dh->prime_len) {
+		size_t pad = dh->prime_len - pub_len;
+		os_memmove(ret_pub + pad, ret_pub, pub_len);
+		os_memset(ret_pub, 0, pad);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
+		    ret_pub, dh->prime_len);
+
+	return 0;
+}
+
+
+static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
+		       size_t data_len, const u8 *data2, size_t data2_len,
+		       u8 *res)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	size_t num_elem = 1;
+
+	addr[0] = data;
+	len[0] = data_len;
+	if (data2) {
+		num_elem++;
+		addr[1] = data2;
+		len[1] = data2_len;
+	}
+
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+					  res);
+	return -1;
+}
+
+
+static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
+				 size_t data_len, u8 *res, size_t len)
+{
+	u8 hash[SHA1_MAC_LEN];
+	u8 idx;
+	const u8 *addr[3];
+	size_t vlen[3];
+	int ret;
+
+	idx = 0;
+	addr[0] = hash;
+	vlen[0] = SHA1_MAC_LEN;
+	addr[1] = data;
+	vlen[1] = data_len;
+	addr[2] = &idx;
+	vlen[2] = 1;
+
+	while (len > 0) {
+		idx++;
+		if (idx == 1)
+			ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
+					       &vlen[1], hash);
+		else
+			ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
+					       hash);
+		if (ret < 0)
+			return -1;
+		if (len > SHA1_MAC_LEN) {
+			os_memcpy(res, hash, SHA1_MAC_LEN);
+			res += SHA1_MAC_LEN;
+			len -= SHA1_MAC_LEN;
+		} else {
+			os_memcpy(res, hash, len);
+			len = 0;
+		}
+	}
+
+	return 0;
+}
+
+
+static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+				   size_t data_len, u8 *res, size_t len)
+{
+	u8 hash[SHA256_MAC_LEN];
+	u8 idx;
+	const u8 *addr[3];
+	size_t vlen[3];
+	int ret;
+
+	idx = 0;
+	addr[0] = hash;
+	vlen[0] = SHA256_MAC_LEN;
+	addr[1] = data;
+	vlen[1] = data_len;
+	addr[2] = &idx;
+	vlen[2] = 1;
+
+	while (len > 0) {
+		idx++;
+		if (idx == 1)
+			ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
+						 &vlen[1], hash);
+		else
+			ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
+						 hash);
+		if (ret < 0)
+			return -1;
+		if (len > SHA256_MAC_LEN) {
+			os_memcpy(res, hash, SHA256_MAC_LEN);
+			res += SHA256_MAC_LEN;
+			len -= SHA256_MAC_LEN;
+		} else {
+			os_memcpy(res, hash, len);
+			len = 0;
+		}
+	}
+
+	return 0;
+}
+
+
+static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
+			   const u8 *data, size_t data_len, u8 *res, size_t len)
+{
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
+					     len);
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
+					       res, len);
+	return -1;
+}
+
+
+int eap_eke_derive_key(struct eap_eke_session *sess,
+		       const u8 *password, size_t password_len,
+		       const u8 *id_s, size_t id_s_len, const u8 *id_p,
+		       size_t id_p_len, u8 *key)
+{
+	u8 zeros[EAP_EKE_MAX_HASH_LEN];
+	u8 temp[EAP_EKE_MAX_HASH_LEN];
+	size_t key_len = 16; /* Only AES-128-CBC is used here */
+	u8 *id;
+
+	/* temp = prf(0+, password) */
+	os_memset(zeros, 0, sess->prf_len);
+	if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
+			password, password_len, NULL, 0, temp) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
+			temp, sess->prf_len);
+
+	/* key = prf+(temp, ID_S | ID_P) */
+	id = os_malloc(id_s_len + id_p_len);
+	if (id == NULL)
+		return -1;
+	os_memcpy(id, id_s, id_s_len);
+	os_memcpy(id + id_s_len, id_p, id_p_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
+			  id, id_s_len + id_p_len);
+	if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
+			    id, id_s_len + id_p_len, key, key_len) < 0) {
+		os_free(id);
+		return -1;
+	}
+	os_free(id);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
+			key, key_len);
+
+	return 0;
+}
+
+
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+		   u8 *ret_dhcomp)
+{
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+	int dh_len;
+	u8 iv[AES_BLOCK_SIZE];
+
+	dh_len = eap_eke_dh_len(sess->dhgroup);
+	if (dh_len < 0)
+		return -1;
+
+	/*
+	 * DHComponent = Encr(key, y)
+	 *
+	 * All defined DH groups use primes that have length devisible by 16, so
+	 * no need to do extra padding for y (= pub).
+	 */
+	if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+	if (random_get_bytes(iv, AES_BLOCK_SIZE))
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
+		    iv, AES_BLOCK_SIZE);
+	os_memcpy(pub, dhpub, dh_len);
+	if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
+		return -1;
+	os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
+	os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
+		    ret_dhcomp, AES_BLOCK_SIZE + dh_len);
+
+	return 0;
+}
+
+
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+			  const u8 *dhpriv, const u8 *peer_dhcomp)
+{
+	u8 zeros[EAP_EKE_MAX_HASH_LEN];
+	u8 peer_pub[EAP_EKE_MAX_DH_LEN];
+	u8 modexp[EAP_EKE_MAX_DH_LEN];
+	size_t len;
+	const struct dh_group *dh;
+
+	if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+
+	dh = eap_eke_dh_group(sess->dhgroup);
+	if (dh == NULL)
+		return -1;
+
+	/* Decrypt peer DHComponent */
+	os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
+	if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
+			peer_pub, dh->prime_len);
+
+	/* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
+	len = dh->prime_len;
+	if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
+			   dh->prime, dh->prime_len, modexp, &len) < 0)
+		return -1;
+	if (len < dh->prime_len) {
+		size_t pad = dh->prime_len - len;
+		os_memmove(modexp + pad, modexp, len);
+		os_memset(modexp, 0, pad);
+	}
+
+	os_memset(zeros, 0, sess->auth_len);
+	if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
+			NULL, 0, sess->shared_secret) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
+			sess->shared_secret, sess->auth_len);
+
+	return 0;
+}
+
+
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+			 const u8 *id_s, size_t id_s_len,
+			 const u8 *id_p, size_t id_p_len)
+{
+	u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
+	size_t ke_len, ki_len;
+	u8 *data;
+	size_t data_len;
+	const char *label = "EAP-EKE Keys";
+	size_t label_len;
+
+	/*
+	 * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
+	 * Ke = encryption key
+	 * Ki = integrity protection key
+	 * Length of each key depends on the selected algorithms.
+	 */
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		ke_len = 16;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		ki_len = 20;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		ki_len = 32;
+	else
+		return -1;
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	os_memcpy(data, label, label_len);
+	os_memcpy(data + label_len, id_s, id_s_len);
+	os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, buf, ke_len + ki_len) < 0) {
+		os_free(data);
+		return -1;
+	}
+
+	os_memcpy(sess->ke, buf, ke_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
+	os_memcpy(sess->ki, buf + ke_len, ki_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
+
+	os_free(data);
+	return 0;
+}
+
+
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+		      const u8 *id_s, size_t id_s_len,
+		      const u8 *id_p, size_t id_p_len,
+		      const u8 *nonce_p, const u8 *nonce_s)
+{
+	u8 *data, *pos;
+	size_t data_len;
+	const char *label = "EAP-EKE Ka";
+	size_t label_len;
+
+	/*
+	 * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
+	 *	     Nonce_S)
+	 * Ka = authentication key
+	 * Length of the key depends on the selected algorithms.
+	 */
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	os_memcpy(pos, label, label_len);
+	pos += label_len;
+	os_memcpy(pos, id_s, id_s_len);
+	pos += id_s_len;
+	os_memcpy(pos, id_p, id_p_len);
+	pos += id_p_len;
+	os_memcpy(pos, nonce_p, sess->nonce_len);
+	pos += sess->nonce_len;
+	os_memcpy(pos, nonce_s, sess->nonce_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, sess->ka, sess->prf_len) < 0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
+
+	return 0;
+}
+
+
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+		       const u8 *id_s, size_t id_s_len,
+		       const u8 *id_p, size_t id_p_len,
+		       const u8 *nonce_p, const u8 *nonce_s,
+		       u8 *msk, u8 *emsk)
+{
+	u8 *data, *pos;
+	size_t data_len;
+	const char *label = "EAP-EKE Exported Keys";
+	size_t label_len;
+	u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+	/*
+	 * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
+	 *		     ID_P | Nonce_P | Nonce_S)
+	 */
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	os_memcpy(pos, label, label_len);
+	pos += label_len;
+	os_memcpy(pos, id_s, id_s_len);
+	pos += id_s_len;
+	os_memcpy(pos, id_p, id_p_len);
+	pos += id_p_len;
+	os_memcpy(pos, nonce_p, sess->nonce_len);
+	pos += sess->nonce_len;
+	os_memcpy(pos, nonce_s, sess->nonce_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
+	    0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+
+	os_memcpy(msk, buf, EAP_MSK_LEN);
+	os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+	os_memset(buf, 0, sizeof(buf));
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
+
+	return 0;
+}
+
+
+static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
+		       u8 *res)
+{
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
+	if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
+	return -1;
+}
+
+
+int eap_eke_prot(struct eap_eke_session *sess,
+		 const u8 *data, size_t data_len,
+		 u8 *prot, size_t *prot_len)
+{
+	size_t block_size, icv_len, pad;
+	u8 *pos, *iv, *e;
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		block_size = AES_BLOCK_SIZE;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		icv_len = SHA1_MAC_LEN;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		icv_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	pad = data_len % block_size;
+	if (pad)
+		pad = block_size - pad;
+
+	if (*prot_len < block_size + data_len + pad + icv_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+	}
+	pos = prot;
+
+	if (random_get_bytes(pos, block_size))
+		return -1;
+	iv = pos;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
+	pos += block_size;
+
+	e = pos;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	if (pad) {
+		if (random_get_bytes(pos, pad))
+			return -1;
+		pos += pad;
+	}
+
+	if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
+		return -1;
+
+	if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+		return -1;
+	pos += icv_len;
+
+	*prot_len = pos - prot;
+	return 0;
+}
+
+
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+			 const u8 *prot, size_t prot_len,
+			 u8 *data, size_t *data_len)
+{
+	size_t block_size, icv_len;
+	u8 icv[EAP_EKE_MAX_HASH_LEN];
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		block_size = AES_BLOCK_SIZE;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		icv_len = SHA1_MAC_LEN;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		icv_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	if (prot_len < 2 * block_size + icv_len)
+		return -1;
+	if ((prot_len - icv_len) % block_size)
+		return -1;
+
+	if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
+			prot_len - block_size - icv_len, icv) < 0)
+		return -1;
+	if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
+		return -1;
+	}
+
+	if (*data_len < prot_len - block_size - icv_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
+		return -1;
+	}
+
+	*data_len = prot_len - block_size - icv_len;
+	os_memcpy(data, prot + block_size, *data_len);
+	if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
+			data, *data_len);
+
+	return 0;
+}
+
+
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+		 const struct wpabuf *msgs, u8 *auth)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
+			sess->ka, sess->auth_len);
+	wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
+	return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
+			   (const u8 *) label, os_strlen(label),
+			   wpabuf_head(msgs), wpabuf_len(msgs), auth);
+}
+
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+			 u8 prf, u8 mac)
+{
+	sess->dhgroup = dhgroup;
+	sess->encr = encr;
+	sess->prf = prf;
+	sess->mac = mac;
+
+	sess->prf_len = eap_eke_prf_len(prf);
+	if (sess->prf_len < 0)
+		return -1;
+	sess->nonce_len = eap_eke_nonce_len(prf);
+	if (sess->nonce_len < 0)
+		return -1;
+	sess->auth_len = eap_eke_auth_len(prf);
+	if (sess->auth_len < 0)
+		return -1;
+	sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
+	if (sess->dhcomp_len < 0)
+		return -1;
+	sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
+	if (sess->pnonce_len < 0)
+		return -1;
+	sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
+	if (sess->pnonce_ps_len < 0)
+		return -1;
+
+	return 0;
+}
+
+
+void eap_eke_session_clean(struct eap_eke_session *sess)
+{
+	os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
+	os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
+	os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
+	os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
+}
diff --git a/src/eap_common/eap_eke_common.h b/src/eap_common/eap_eke_common.h
new file mode 100644
index 0000000..a4c0422
--- /dev/null
+++ b/src/eap_common/eap_eke_common.h
@@ -0,0 +1,114 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_EKE_COMMON_H
+#define EAP_EKE_COMMON_H
+
+/* EKE Exchange */
+#define EAP_EKE_ID 1
+#define EAP_EKE_COMMIT 2
+#define EAP_EKE_CONFIRM 3
+#define EAP_EKE_FAILURE 4
+
+/* Diffie-Hellman Group Registry */
+#define EAP_EKE_DHGROUP_EKE_2 1
+#define EAP_EKE_DHGROUP_EKE_5 2
+#define EAP_EKE_DHGROUP_EKE_14 3 /* mandatory to implement */
+#define EAP_EKE_DHGROUP_EKE_15 4
+#define EAP_EKE_DHGROUP_EKE_16 5
+
+/* Encryption Algorithm Registry */
+#define EAP_EKE_ENCR_AES128_CBC 1 /* mandatory to implement */
+
+/* Pseudo Random Function Registry */
+#define EAP_EKE_PRF_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_PRF_HMAC_SHA2_256 2
+
+/* Keyed Message Digest (MAC) Registry */
+#define EAP_EKE_MAC_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_MAC_HMAC_SHA2_256 2
+
+/* Identity Type Registry */
+#define EAP_EKE_ID_OPAQUE 1
+#define EAP_EKE_ID_NAI 2
+#define EAP_EKE_ID_IPv4 3
+#define EAP_EKE_ID_IPv6 4
+#define EAP_EKE_ID_FQDN 5
+#define EAP_EKE_ID_DN 6
+
+/* Failure-Code */
+#define EAP_EKE_FAIL_NO_ERROR 1
+#define EAP_EKE_FAIL_PROTO_ERROR 2
+#define EAP_EKE_FAIL_PASSWD_NOT_FOUND 3
+#define EAP_EKE_FAIL_AUTHENTICATION_FAIL 4
+#define EAP_EKE_FAIL_AUTHORIZATION_FAIL 5
+#define EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN 6
+#define EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR 0xffffffff
+
+#define EAP_EKE_MAX_DH_LEN 512
+#define EAP_EKE_MAX_HASH_LEN 32
+#define EAP_EKE_MAX_KEY_LEN 16
+#define EAP_EKE_MAX_KE_LEN 16
+#define EAP_EKE_MAX_KI_LEN 32
+#define EAP_EKE_MAX_KA_LEN 32
+#define EAP_EKE_MAX_NONCE_LEN 16
+
+struct eap_eke_session {
+	/* Selected proposal */
+	u8 dhgroup;
+	u8 encr;
+	u8 prf;
+	u8 mac;
+
+	u8 shared_secret[EAP_EKE_MAX_HASH_LEN];
+	u8 ke[EAP_EKE_MAX_KE_LEN];
+	u8 ki[EAP_EKE_MAX_KI_LEN];
+	u8 ka[EAP_EKE_MAX_KA_LEN];
+
+	int prf_len;
+	int nonce_len;
+	int auth_len;
+	int dhcomp_len;
+	int pnonce_len;
+	int pnonce_ps_len;
+};
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+			 u8 prf, u8 mac);
+void eap_eke_session_clean(struct eap_eke_session *sess);
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub);
+int eap_eke_derive_key(struct eap_eke_session *sess,
+		       const u8 *password, size_t password_len,
+		       const u8 *id_s, size_t id_s_len, const u8 *id_p,
+		       size_t id_p_len, u8 *key);
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+		   u8 *ret_dhcomp);
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+			  const u8 *dhpriv, const u8 *peer_dhcomp);
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+			 const u8 *id_s, size_t id_s_len,
+			 const u8 *id_p, size_t id_p_len);
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+		      const u8 *id_s, size_t id_s_len,
+		      const u8 *id_p, size_t id_p_len,
+		      const u8 *nonce_p, const u8 *nonce_s);
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+		       const u8 *id_s, size_t id_s_len,
+		       const u8 *id_p, size_t id_p_len,
+		       const u8 *nonce_p, const u8 *nonce_s,
+		       u8 *msk, u8 *emsk);
+int eap_eke_prot(struct eap_eke_session *sess,
+		 const u8 *data, size_t data_len,
+		 u8 *prot, size_t *prot_len);
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+			 const u8 *prot, size_t prot_len,
+			 u8 *data, size_t *data_len);
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+		 const struct wpabuf *msgs, u8 *auth);
+
+#endif /* EAP_EKE_COMMON_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 4df8853..c0d7078 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -406,9 +406,11 @@
 		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
 					       &sm->eapKeyDataLen);
 		os_free(sm->eapSessionId);
-		sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
-						       &sm->eapSessionIdLen);
-		if (sm->eapSessionId) {
+		sm->eapSessionId = NULL;
+		if (sm->m->getSessionId) {
+			sm->eapSessionId = sm->m->getSessionId(
+				sm, sm->eap_method_priv,
+				&sm->eapSessionIdLen);
 			wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
 				    sm->eapSessionId, sm->eapSessionIdLen);
 		}
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index ed90919..42f525b 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
 /*
  * EAP peer configuration data
- * Copyright (c) 2003-2008, 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.
@@ -634,6 +634,15 @@
 	 *         password field is the name of that external entry
 	 */
 	u32 flags;
+
+	/**
+	 * ocsp - Whether to use/require OCSP to check server certificate
+	 *
+	 * 0 = do not use OCSP stapling (TLS certificate status extension)
+	 * 1 = try to use OCSP stapling, but not require response
+	 * 2 = require valid OCSP stapling response
+	 */
+	int ocsp;
 };
 
 
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
new file mode 100644
index 0000000..c71db5f
--- /dev/null
+++ b/src/eap_peer/eap_eke.c
@@ -0,0 +1,723 @@
+/*
+ * EAP peer method: EAP-EKE (RFC 6124)
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+struct eap_eke_data {
+	enum {
+		IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
+	} state;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 *peerid;
+	size_t peerid_len;
+	u8 *serverid;
+	size_t serverid_len;
+	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+	struct eap_eke_session sess;
+	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+	struct wpabuf *msgs;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case COMMIT:
+		return "COMMIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+		   eap_eke_state_txt(data->state), eap_eke_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+	struct eap_eke_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (!password) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	eap_eke_state(data, IDENTITY);
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity) {
+		data->peerid = os_malloc(identity_len);
+		if (data->peerid == NULL) {
+			eap_eke_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->peerid, identity, identity_len);
+		data->peerid_len = identity_len;
+	}
+
+	return data;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	eap_eke_session_clean(&data->sess);
+	os_free(data->serverid);
+	os_free(data->peerid);
+	wpabuf_free(data->msgs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
+					 size_t length, u8 eke_exch)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = 1 + length;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+		return NULL;
+	}
+
+	wpabuf_put_u8(msg, eke_exch);
+
+	return msg;
+}
+
+
+static int eap_eke_supp_dhgroup(u8 dhgroup)
+{
+	return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_16;
+}
+
+
+static int eap_eke_supp_encr(u8 encr)
+{
+	return encr == EAP_EKE_ENCR_AES128_CBC;
+}
+
+
+static int eap_eke_supp_prf(u8 prf)
+{
+	return prf == EAP_EKE_PRF_HMAC_SHA1 ||
+		prf == EAP_EKE_PRF_HMAC_SHA2_256;
+}
+
+
+static int eap_eke_supp_mac(u8 mac)
+{
+	return mac == EAP_EKE_MAC_HMAC_SHA1 ||
+		mac == EAP_EKE_MAC_HMAC_SHA2_256;
+}
+
+
+static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
+					  struct eap_method_ret *ret,
+					  const struct wpabuf *reqData,
+					  u32 failure_code)
+{
+	struct wpabuf *resp;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
+		   failure_code);
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
+	if (resp)
+		wpabuf_put_be32(resp, failure_code);
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, FAILURE);
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
+					  struct eap_method_ret *ret,
+					  const struct wpabuf *reqData,
+					  const u8 *payload,
+					  size_t payload_len)
+{
+	struct wpabuf *resp;
+	unsigned num_prop, i;
+	const u8 *pos, *end;
+	const u8 *prop = NULL;
+	u8 idtype;
+
+	if (data->state != IDENTITY) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
+
+	if (payload_len < 2 + 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	pos = payload;
+	end = payload + payload_len;
+
+	num_prop = *pos++;
+	pos++; /* Ignore Reserved field */
+
+	if (pos + num_prop * 4 > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
+			   num_prop);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	for (i = 0; i < num_prop; i++) {
+		const u8 *tmp = pos;
+
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
+			   i, pos[0], pos[1], pos[2], pos[3]);
+		pos += 4;
+
+		if (!eap_eke_supp_dhgroup(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_encr(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_prf(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_mac(*tmp))
+			continue;
+
+		prop = tmp - 3;
+		if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
+					 prop[3]) < 0) {
+			prop = NULL;
+			continue;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
+		break;
+	}
+
+	if (prop == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
+	}
+
+	pos += (num_prop - i - 1) * 4;
+
+	if (pos == end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	idtype = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
+			  pos, end - pos);
+	os_free(data->serverid);
+	data->serverid = os_malloc(end - pos);
+	if (data->serverid == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	os_memcpy(data->serverid, pos, end - pos);
+	data->serverid_len = end - pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 2 + 4 + 1 + data->peerid_len,
+				 EAP_EKE_ID);
+	if (resp == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	wpabuf_put_u8(resp, 1); /* NumProposals */
+	wpabuf_put_u8(resp, 0); /* Reserved */
+	wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
+	wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
+	if (data->peerid)
+		wpabuf_put_data(resp, data->peerid, data->peerid_len);
+
+	wpabuf_free(data->msgs);
+	data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
+	if (data->msgs == NULL) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put_buf(data->msgs, reqData);
+	wpabuf_put_buf(data->msgs, resp);
+
+	eap_eke_state(data, COMMIT);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
+					      struct eap_eke_data *data,
+					      struct eap_method_ret *ret,
+					      const struct wpabuf *reqData,
+					      const u8 *payload,
+					      size_t payload_len)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *end, *dhcomp;
+	size_t prot_len;
+	u8 *rpos;
+	u8 key[EAP_EKE_MAX_KEY_LEN];
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+	const u8 *password;
+	size_t password_len;
+
+	if (data->state != COMMIT) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+	}
+
+	pos = payload;
+	end = payload + payload_len;
+
+	if (pos + data->sess.dhcomp_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
+		    pos, data->sess.dhcomp_len);
+	dhcomp = pos;
+	pos += data->sess.dhcomp_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+	/*
+	 * temp = prf(0+, password)
+	 * key = prf+(temp, ID_S | ID_P)
+	 */
+	if (eap_eke_derive_key(&data->sess, password, password_len,
+			       data->serverid, data->serverid_len,
+			       data->peerid, data->peerid_len, key) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	/*
+	 * y_p = g ^ x_p (mod p)
+	 * x_p = random number 2 .. p-1
+	 */
+	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
+	{
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_derive_ke_ki(&data->sess,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 data->sess.dhcomp_len + data->sess.pnonce_len,
+				 EAP_EKE_COMMIT);
+	if (resp == NULL) {
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	/* DHComponent_P = Encr(key, y_p) */
+	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
+	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	os_memset(key, 0, sizeof(key));
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+		    rpos, data->sess.dhcomp_len);
+
+	if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+			data->nonce_p, data->sess.nonce_len);
+	prot_len = wpabuf_tailroom(resp);
+	if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
+			 wpabuf_put(resp, 0), &prot_len) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
+		    wpabuf_put(resp, 0), prot_len);
+	wpabuf_put(resp, prot_len);
+
+	/* TODO: CBValue */
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
+	    < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put_buf(data->msgs, reqData);
+	wpabuf_put_buf(data->msgs, resp);
+
+	eap_eke_state(data, CONFIRM);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	size_t prot_len;
+	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+	u8 auth_s[EAP_EKE_MAX_HASH_LEN];
+	size_t decrypt_len;
+	u8 *auth;
+
+	if (data->state != CONFIRM) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
+			   data->state);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
+
+	pos = payload;
+	end = payload + payload_len;
+
+	if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	decrypt_len = sizeof(nonces);
+	if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
+				 nonces, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+	if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
+			nonces, 2 * data->sess.nonce_len);
+	if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+
+	os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
+		  data->sess.nonce_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+			data->nonce_s, data->sess.nonce_len);
+
+	if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
+			      data->peerid, data->peerid_len,
+			      data->nonce_p, data->nonce_s) < 0) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
+	{
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
+	if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
+		      data->sess.prf_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 data->sess.pnonce_len + data->sess.prf_len,
+				 EAP_EKE_CONFIRM);
+	if (resp == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	prot_len = wpabuf_tailroom(resp);
+	if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
+			 wpabuf_put(resp, 0), &prot_len) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put(resp, prot_len);
+
+	auth = wpabuf_put(resp, data->sess.prf_len);
+	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
+
+	if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
+			       data->peerid, data->peerid_len,
+			       data->nonce_s, data->nonce_p,
+			       data->msk, data->emsk) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, SUCCESS);
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
+
+	if (payload_len < 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+	} else {
+		u32 code;
+		code = WPA_GET_BE32(payload);
+		wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
+	}
+
+	return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
+}
+
+
+static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_eke_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	size_t len;
+	u8 eke_exch;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	end = pos + len;
+	eke_exch = *pos++;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	switch (eke_exch) {
+	case EAP_EKE_ID:
+		resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
+		break;
+	case EAP_EKE_COMMIT:
+		resp = eap_eke_process_commit(sm, data, ret, reqData,
+					      pos, end - pos);
+		break;
+	case EAP_EKE_CONFIRM:
+		resp = eap_eke_process_confirm(data, ret, reqData,
+					       pos, end - pos);
+		break;
+	case EAP_EKE_FAILURE:
+		resp = eap_eke_process_failure(data, ret, reqData,
+					       pos, end - pos);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (ret->methodState == METHOD_DONE)
+		ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+int eap_peer_eke_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_eke_init;
+	eap->deinit = eap_eke_deinit;
+	eap->process = eap_eke_process;
+	eap->isKeyAvailable = eap_eke_isKeyAvailable;
+	eap->getKey = eap_eke_getKey;
+	eap->get_emsk = eap_eke_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index 4994ff1..a465fd2 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -105,5 +105,6 @@
 int eap_peer_vendor_test_register(void);
 int eap_peer_tnc_register(void);
 int eap_peer_pwd_register(void);
+int eap_peer_eke_register(void);
 
 #endif /* EAP_METHODS_H */
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index fb6c282..f9aa742 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -644,10 +644,8 @@
 	 * must allocate a large enough temporary buffer to create that since
 	 * the received message does not include nul termination.
 	 */
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msdata, len);
 	if (buf) {
-		os_memcpy(buf, msdata, len);
-		buf[len] = '\0';
 		retry = eap_mschapv2_failure_txt(sm, data, buf);
 		os_free(buf);
 	}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index a777bb0..be8c301 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2012, 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.
@@ -164,6 +164,10 @@
 {
 	int res;
 
+	if (config->ocsp)
+		params->flags |= TLS_CONN_REQUEST_OCSP;
+	if (config->ocsp == 2)
+		params->flags |= TLS_CONN_REQUIRE_OCSP;
 	data->conn = tls_connection_init(data->ssl_ctx);
 	if (data->conn == NULL) {
 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index f5edfd5..a3ec395 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -741,12 +741,10 @@
 	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
 	int recommendation_msg = 0;
 
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msg, len);
 	if (buf == NULL)
 		return TNCCS_PROCESS_ERROR;
 
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
 	start = os_strstr(buf, "<TNCCS-Batch ");
 	end = os_strstr(buf, "</TNCCS-Batch>");
 	if (start == NULL || end == NULL || start > end) {
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index f2a7cd7..36b230b 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -104,6 +104,9 @@
 	int fragment_size;
 
 	int pbc_in_m1;
+
+	const u8 *server_id;
+	size_t server_id_len;
 };
 
 
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index f92704a..003e202 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -188,6 +188,9 @@
 	int fragment_size;
 
 	int pbc_in_m1;
+
+	const u8 *server_id;
+	size_t server_id_len;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index bc810a9..429cb72 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -45,5 +45,6 @@
 int eap_server_ikev2_register(void);
 int eap_server_tnc_register(void);
 int eap_server_pwd_register(void);
+int eap_server_eke_register(void);
 
 #endif /* EAP_SERVER_METHODS_H */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 15f7e22..54b7533 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1278,6 +1278,8 @@
 	sm->fragment_size = conf->fragment_size;
 	sm->pwd_group = conf->pwd_group;
 	sm->pbc_in_m1 = conf->pbc_in_m1;
+	sm->server_id = conf->server_id;
+	sm->server_id_len = conf->server_id_len;
 
 	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
new file mode 100644
index 0000000..b19a321
--- /dev/null
+++ b/src/eap_server/eap_server_eke.c
@@ -0,0 +1,793 @@
+/*
+ * hostapd / EAP-EKE (RFC 6124) server
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+
+struct eap_eke_data {
+	enum {
+		IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE
+	} state;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 *peerid;
+	size_t peerid_len;
+	u8 peerid_type;
+	u8 serverid_type;
+	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+	u8 key[EAP_EKE_MAX_KEY_LEN];
+	struct eap_eke_session sess;
+	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+	struct wpabuf *msgs;
+	int phase2;
+	u32 failure_code;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case COMMIT:
+		return "COMMIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case FAILURE_REPORT:
+		return "FAILURE_REPORT";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+		   eap_eke_state_txt(data->state),
+		   eap_eke_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_eke_fail(struct eap_eke_data *data, u32 code)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
+	data->failure_code = code;
+	eap_eke_state(data, FAILURE_REPORT);
+}
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+	struct eap_eke_data *data;
+	size_t i;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	eap_eke_state(data, IDENTITY);
+
+	data->serverid_type = EAP_EKE_ID_OPAQUE;
+	for (i = 0; i < sm->server_id_len; i++) {
+		if (sm->server_id[i] == '.' &&
+		    data->serverid_type == EAP_EKE_ID_OPAQUE)
+			data->serverid_type = EAP_EKE_ID_FQDN;
+		if (sm->server_id[i] == '@')
+			data->serverid_type = EAP_EKE_ID_NAI;
+	}
+
+	data->phase2 = sm->init_phase2;
+
+	return data;
+}
+
+
+static void eap_eke_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	eap_eke_session_clean(&data->sess);
+	os_free(data->peerid);
+	wpabuf_free(data->msgs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data,
+					 u8 id, size_t length, u8 eke_exch)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = 1 + length;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+			    EAP_CODE_REQUEST, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+		return NULL;
+	}
+
+	wpabuf_put_u8(msg, eke_exch);
+
+	return msg;
+}
+
+
+static int supported_proposal(const u8 *pos)
+{
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA1)
+		return 1;
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
+		   data->failure_code);
+
+	msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
+	if (msg == NULL) {
+		eap_eke_state(data, FAILURE);
+		return NULL;
+	}
+	wpabuf_put_be32(msg, data->failure_code);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
+					      struct eap_eke_data *data,
+					      u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
+
+	plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+	msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 4); /* NumProposals */
+	wpabuf_put_u8(msg, 0); /* Reserved */
+
+	/* Proposal - DH Group 16 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/* Proposal - DH Group 15 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/* Proposal - DH Group 14 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/*
+	 * Proposal - DH Group 14 with AES128-CBC and SHA1
+	 * (mandatory to implement algorithms)
+	 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
+
+	/* Server IDType + Identity */
+	wpabuf_put_u8(msg, data->serverid_type);
+	wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+
+	wpabuf_free(data->msgs);
+	data->msgs = wpabuf_dup(msg);
+	if (data->msgs == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
+					    struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (eap_eke_derive_key(&data->sess, sm->user->password,
+			       sm->user->password_len,
+			       sm->server_id, sm->server_id_len,
+			       data->peerid, data->peerid_len, data->key) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
+				EAP_EKE_COMMIT);
+	if (msg == NULL) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	/*
+	 * y_s = g ^ x_s (mod p)
+	 * x_s = random number 2 .. p-1
+	 * temp = prf(0+, password)
+	 * key = prf+(temp, ID_S | ID_P)
+	 * DHComponent_S = Encr(key, y_s)
+	 */
+
+	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (eap_eke_dhcomp(&data->sess, data->key, pub,
+			   wpabuf_put(msg, data->sess.dhcomp_len))
+	    < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpabuf_put_buf(data->msgs, msg);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
+					     struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen, prot_len;
+	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+	u8 *auth;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
+
+	plen = data->sess.pnonce_ps_len + data->sess.prf_len;
+	msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
+	if (msg == NULL) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+			data->nonce_s, data->sess.nonce_len);
+
+	os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
+	os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
+		  data->sess.nonce_len);
+	prot_len = wpabuf_tailroom(msg);
+	if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
+			 wpabuf_put(msg, 0), &prot_len) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpabuf_put(msg, prot_len);
+
+	if (eap_eke_derive_ka(&data->sess,
+			      sm->server_id, sm->server_id_len,
+			      data->peerid, data->peerid_len,
+			      data->nonce_p, data->nonce_s) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	auth = wpabuf_put(msg, data->sess.prf_len);
+	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_eke_data *data = priv;
+
+	switch (data->state) {
+	case IDENTITY:
+		return eap_eke_build_identity(sm, data, id);
+	case COMMIT:
+		return eap_eke_build_commit(sm, data, id);
+	case CONFIRM:
+		return eap_eke_build_confirm(sm, data, id);
+	case FAILURE_REPORT:
+		return eap_eke_build_failure(data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_eke_data *data = priv;
+	size_t len;
+	const u8 *pos;
+	u8 eke_exch;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
+		return TRUE;
+	}
+
+	eke_exch = *pos;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
+
+	if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
+		return FALSE;
+
+	if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
+		return FALSE;
+
+	if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
+		return FALSE;
+
+	if (eke_exch == EAP_EKE_FAILURE)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
+		   eke_exch, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_eke_process_identity(struct eap_sm *sm,
+				     struct eap_eke_data *data,
+				     const struct wpabuf *respData,
+				     const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
+
+	if (data->state != IDENTITY) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (pos + 2 + 4 + 1 > end) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	if (*pos != 1) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
+			   *pos);
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos += 2;
+
+	if (!supported_proposal(pos)) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
+			   pos[0], pos[1], pos[2], pos[3]);
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
+		   pos[0], pos[1], pos[2], pos[3]);
+	if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
+	    0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	pos += 4;
+
+	data->peerid_type = *pos++;
+	os_free(data->peerid);
+	data->peerid = os_malloc(end - pos);
+	if (data->peerid == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	os_memcpy(data->peerid, pos, end - pos);
+	data->peerid_len = end - pos;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
+			  data->peerid, data->peerid_len);
+
+	if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_EKE)
+			break;
+	}
+	if (i == EAP_MAX_METHODS) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	if (sm->user->password == NULL || sm->user->password_len == 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpabuf_put_buf(data->msgs, respData);
+
+	eap_eke_state(data, COMMIT);
+}
+
+
+static void eap_eke_process_commit(struct eap_sm *sm,
+				   struct eap_eke_data *data,
+				   const struct wpabuf *respData,
+				   const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end, *dhcomp, *pnonce;
+	size_t decrypt_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
+
+	if (data->state != COMMIT) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+		    pos, data->sess.dhcomp_len);
+	dhcomp = pos;
+	pos += data->sess.dhcomp_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
+	pnonce = pos;
+	pos += data->sess.pnonce_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+	if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
+	    < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	if (eap_eke_derive_ke_ki(&data->sess,
+				 sm->server_id, sm->server_id_len,
+				 data->peerid, data->peerid_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	decrypt_len = sizeof(data->nonce_p);
+	if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
+				 data->nonce_p, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	if (decrypt_len < (size_t) data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+			data->nonce_p, data->sess.nonce_len);
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpabuf_put_buf(data->msgs, respData);
+
+	eap_eke_state(data, CONFIRM);
+}
+
+
+static void eap_eke_process_confirm(struct eap_sm *sm,
+				    struct eap_eke_data *data,
+				    const struct wpabuf *respData,
+				    const u8 *payload, size_t payloadlen)
+{
+	size_t decrypt_len;
+	u8 nonce[EAP_EKE_MAX_NONCE_LEN];
+	u8 auth_p[EAP_EKE_MAX_HASH_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+	if (data->state != CONFIRM) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+	if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	decrypt_len = sizeof(nonce);
+	if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
+				 nonce, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	if (decrypt_len < (size_t) data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
+			nonce, data->sess.nonce_len);
+	if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+
+	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
+	if (os_memcmp(auth_p, payload + data->sess.pnonce_len,
+		      data->sess.prf_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+
+	if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+			       data->peerid, data->peerid_len,
+			       data->nonce_s, data->nonce_p,
+			       data->msk, data->emsk) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	os_memset(data->key, 0, sizeof(data->key));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, SUCCESS);
+}
+
+
+static void eap_eke_process_failure(struct eap_sm *sm,
+				    struct eap_eke_data *data,
+				    const struct wpabuf *respData,
+				    const u8 *payload, size_t payloadlen)
+{
+	u32 code;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
+
+	if (payloadlen < 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+		eap_eke_state(data, FAILURE);
+		return;
+	}
+
+	code = WPA_GET_BE32(payload);
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
+
+	eap_eke_state(data, FAILURE);
+}
+
+
+static void eap_eke_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_eke_data *data = priv;
+	u8 eke_exch;
+	size_t len;
+	const u8 *pos, *end;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	eke_exch = *pos;
+	end = pos + len;
+	pos++;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
+
+	switch (eke_exch) {
+	case EAP_EKE_ID:
+		eap_eke_process_identity(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_COMMIT:
+		eap_eke_process_commit(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_CONFIRM:
+		eap_eke_process_confirm(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_FAILURE:
+		eap_eke_process_failure(sm, data, respData, pos, end - pos);
+		break;
+	}
+}
+
+
+static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_eke_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_eke_init;
+	eap->reset = eap_eke_reset;
+	eap->buildReq = eap_eke_buildReq;
+	eap->check = eap_eke_check;
+	eap->process = eap_eke_process;
+	eap->isDone = eap_eke_isDone;
+	eap->getKey = eap_eke_getKey;
+	eap->isSuccess = eap_eke_isSuccess;
+	eap->get_emsk = eap_eke_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index 2853c48..66f4271 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -26,8 +26,6 @@
 	size_t pk_len;
 	u8 *id_peer;
 	size_t id_peer_len;
-	u8 *id_server;
-	size_t id_server_len;
 #define MAX_NUM_CSUITES 2
 	struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
 	size_t csuite_count;
@@ -71,11 +69,6 @@
 		return NULL;
 	data->state = GPSK_1;
 
-	/* TODO: add support for configuring ID_Server */
-	data->id_server = (u8 *) os_strdup("hostapd");
-	if (data->id_server)
-		data->id_server_len = os_strlen((char *) data->id_server);
-
 	data->csuite_count = 0;
 	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 					   EAP_GPSK_CIPHER_AES)) {
@@ -101,7 +94,6 @@
 static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_gpsk_data *data = priv;
-	os_free(data->id_server);
 	os_free(data->id_peer);
 	os_free(data);
 }
@@ -123,7 +115,7 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
 		    data->rand_server, EAP_GPSK_RAND_LEN);
 
-	len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+	len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
 		data->csuite_count * sizeof(struct eap_gpsk_csuite);
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 			    EAP_CODE_REQUEST, id);
@@ -135,8 +127,8 @@
 	}
 
 	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	wpabuf_put_be16(req, sm->server_id_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
 	wpabuf_put_be16(req,
 			data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -158,7 +150,7 @@
 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
 
 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
+	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
 		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 			    EAP_CODE_REQUEST, id);
@@ -174,8 +166,8 @@
 
 	wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
 	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	wpabuf_put_be16(req, sm->server_id_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 	csuite = wpabuf_put(req, sizeof(*csuite));
 	WPA_PUT_BE32(csuite->vendor, data->vendor);
 	WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -301,8 +293,8 @@
 		eap_gpsk_state(data, FAILURE);
 		return;
 	}
-	if (alen != data->id_server_len ||
-	    os_memcmp(pos, data->id_server, alen) != 0) {
+	if (alen != sm->server_id_len ||
+	    os_memcmp(pos, sm->server_id, alen) != 0) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
 			   "GPSK-2 did not match");
 		eap_gpsk_state(data, FAILURE);
@@ -416,7 +408,7 @@
 				 data->vendor, data->specifier,
 				 data->rand_peer, data->rand_server,
 				 data->id_peer, data->id_peer_len,
-				 data->id_server, data->id_server_len,
+				 sm->server_id, sm->server_id_len,
 				 data->msk, data->emsk,
 				 data->sk, &data->sk_len,
 				 data->pk, &data->pk_len) < 0) {
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 42aaca2..1ada0c8 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -103,8 +103,11 @@
 	data->ikev2.proposal.encr = ENCR_AES_CBC;
 	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
 
-	data->ikev2.IDi = (u8 *) os_strdup("hostapd");
-	data->ikev2.IDi_len = 7;
+	data->ikev2.IDi = os_malloc(sm->server_id_len);
+	if (data->ikev2.IDi == NULL)
+		goto failed;
+	os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
+	data->ikev2.IDi_len = sm->server_id_len;
 
 	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
 	data->ikev2.cb_ctx = sm;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 8d3dd52..3153d2e 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -100,7 +100,6 @@
 {
 	struct wpabuf *req;
 	struct eap_mschapv2_hdr *ms;
-	char *name = "hostapd"; /* TODO: make this configurable */
 	size_t ms_len;
 
 	if (!data->auth_challenge_from_tls &&
@@ -111,7 +110,7 @@
 		return NULL;
 	}
 
-	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
+	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
@@ -133,7 +132,7 @@
 		wpabuf_put(req, CHALLENGE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
 		    data->auth_challenge, CHALLENGE_LEN);
-	wpabuf_put_data(req, name, os_strlen(name));
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
 	return req;
 }
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 0cd9799..46bedd9 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -22,8 +22,8 @@
 	enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
 	u8 rand_s[EAP_PSK_RAND_LEN];
 	u8 rand_p[EAP_PSK_RAND_LEN];
-	u8 *id_p, *id_s;
-	size_t id_p_len, id_s_len;
+	u8 *id_p;
+	size_t id_p_len;
 	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
 	u8 msk[EAP_MSK_LEN];
 	u8 emsk[EAP_EMSK_LEN];
@@ -38,8 +38,6 @@
 	if (data == NULL)
 		return NULL;
 	data->state = PSK_1;
-	data->id_s = (u8 *) "hostapd";
-	data->id_s_len = 7;
 
 	return data;
 }
@@ -70,7 +68,7 @@
 		    data->rand_s, EAP_PSK_RAND_LEN);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			    sizeof(*psk) + data->id_s_len,
+			    sizeof(*psk) + sm->server_id_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -82,7 +80,7 @@
 	psk = wpabuf_put(req, sizeof(*psk));
 	psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
 	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
-	wpabuf_put_data(req, data->id_s, data->id_s_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
 	return req;
 }
@@ -112,13 +110,13 @@
 	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
 
 	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
-	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+	buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
 	buf = os_malloc(buflen);
 	if (buf == NULL)
 		goto fail;
 
-	os_memcpy(buf, data->id_s, data->id_s_len);
-	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+	os_memcpy(buf, sm->server_id, sm->server_id_len);
+	os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
 	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
 		os_free(buf);
 		goto fail;
@@ -296,7 +294,7 @@
 	os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
 
 	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
-	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+	buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		data->state = FAILURE;
@@ -304,8 +302,8 @@
 	}
 	os_memcpy(buf, data->id_p, data->id_p_len);
 	pos = buf + data->id_p_len;
-	os_memcpy(pos, data->id_s, data->id_s_len);
-	pos += data->id_s_len;
+	os_memcpy(pos, sm->server_id, sm->server_id_len);
+	pos += sm->server_id_len;
 	os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
 	pos += EAP_PSK_RAND_LEN;
 	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index f72e1bf..68dd76b 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -27,8 +27,6 @@
 	u8 session_id;
 	u8 *peerid;
 	size_t peerid_len;
-	u8 *serverid;
-	size_t serverid_len;
 };
 
 
@@ -77,11 +75,6 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
 		   data->session_id);
 
-	/* TODO: add support for configuring SERVERID */
-	data->serverid = (u8 *) os_strdup("hostapd");
-	if (data->serverid)
-		data->serverid_len = os_strlen((char *) data->serverid);
-
 	return data;
 }
 
@@ -89,7 +82,6 @@
 static void eap_sake_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_sake_data *data = priv;
-	os_free(data->serverid);
 	os_free(data->peerid);
 	os_free(data);
 }
@@ -131,8 +123,7 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
 
 	plen = 4;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
+	plen += 2 + sm->server_id_len;
 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
 	if (msg == NULL) {
 		data->state = FAILURE;
@@ -142,11 +133,9 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
 	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
 
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+			  sm->server_id, sm->server_id_len);
 
 	return msg;
 }
@@ -169,9 +158,7 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
 		    data->rand_s, EAP_SAKE_RAND_LEN);
 
-	plen = 2 + EAP_SAKE_RAND_LEN;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
+	plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
 	if (msg == NULL) {
 		data->state = FAILURE;
@@ -182,11 +169,9 @@
 	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
 			  data->rand_s, EAP_SAKE_RAND_LEN);
 
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+			  sm->server_id, sm->server_id_len);
 
 	return msg;
 }
@@ -213,7 +198,7 @@
 	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
 	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-				 data->serverid, data->serverid_len,
+				 sm->server_id, sm->server_id_len,
 				 data->peerid, data->peerid_len, 0,
 				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
 	{
@@ -362,7 +347,7 @@
 			     (u8 *) &data->tek, data->msk, data->emsk);
 
 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
+			     sm->server_id, sm->server_id_len,
 			     data->peerid, data->peerid_len, 1,
 			     wpabuf_head(respData), wpabuf_len(respData),
 			     attr.mic_p, mic_p);
@@ -399,7 +384,7 @@
 	}
 
 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
+			     sm->server_id, sm->server_id_len,
 			     data->peerid, data->peerid_len, 1,
 			     wpabuf_head(respData), wpabuf_len(respData),
 			     attr.mic_p, mic_p);
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 257013e..1b9d701 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -1480,7 +1480,6 @@
  */
 char * sim_get_username(const u8 *identity, size_t identity_len)
 {
-	char *username;
 	size_t pos;
 
 	if (identity == NULL)
@@ -1491,11 +1490,5 @@
 			break;
 	}
 
-	username = os_malloc(pos + 1);
-	if (username == NULL)
-		return NULL;
-	os_memcpy(username, identity, pos);
-	username[pos] = '\0';
-
-	return username;
+	return dup_binstr(identity, pos);
 }
diff --git a/src/eap_server/tncs.c b/src/eap_server/tncs.c
index 5e332ae..e429f1e 100644
--- a/src/eap_server/tncs.c
+++ b/src/eap_server/tncs.c
@@ -851,12 +851,10 @@
 	unsigned char *decoded;
 	size_t decoded_len;
 
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msg, len);
 	if (buf == NULL)
 		return TNCCS_PROCESS_ERROR;
 
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
 	start = os_strstr(buf, "<TNCCS-Batch ");
 	end = os_strstr(buf, "</TNCCS-Batch>");
 	if (start == NULL || end == NULL || start > end) {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index c3ccb46..013d781 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -830,6 +830,8 @@
 	eap_conf.fragment_size = eapol->conf.fragment_size;
 	eap_conf.pwd_group = eapol->conf.pwd_group;
 	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
+	eap_conf.server_id = eapol->conf.server_id;
+	eap_conf.server_id_len = eapol->conf.server_id_len;
 	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
 	if (sm->eap == NULL) {
 		eapol_auth_free(sm);
@@ -1045,6 +1047,8 @@
 	os_free(dst->eap_req_id_text);
 	dst->pwd_group = src->pwd_group;
 	dst->pbc_in_m1 = src->pbc_in_m1;
+	dst->server_id = src->server_id;
+	dst->server_id_len = src->server_id_len;
 	if (src->eap_req_id_text) {
 		dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
 		if (dst->eap_req_id_text == NULL)
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index b50bbdd..3a0f450 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -37,6 +37,8 @@
 	int fragment_size;
 	u16 pwd_group;
 	int pbc_in_m1;
+	const u8 *server_id;
+	size_t server_id_len;
 
 	/* Opaque context pointer to owner data for callback functions */
 	void *ctx;
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 2e56086..9b054fc 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1533,6 +1533,10 @@
 {
 	if (sm) {
 		sm->userLogoff = logoff;
+		if (!logoff) {
+			/* If there is a delayed txStart queued, start now. */
+			sm->startWhen = 0;
+		}
 		eapol_sm_step(sm);
 	}
 }
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 2b5e5bd..0a414ee 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -12,7 +12,6 @@
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
 #include "p2p.h"
@@ -119,8 +118,9 @@
 			continue;
 #endif
 
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
-			"entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
+		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)
@@ -210,7 +210,7 @@
 
 void p2p_set_state(struct p2p_data *p2p, int new_state)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
+	p2p_dbg(p2p, "State %s -> %s",
 		p2p_state_txt(p2p->state), p2p_state_txt(new_state));
 	p2p->state = new_state;
 }
@@ -218,8 +218,7 @@
 
 void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Set timeout (state=%s): %u.%06u sec",
+	p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",
 		p2p_state_txt(p2p->state), sec, usec);
 	eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
 	eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
@@ -228,8 +227,7 @@
 
 void p2p_clear_timeout(struct p2p_data *p2p)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear timeout (state=%s)",
-		p2p_state_txt(p2p->state));
+	p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state));
 	eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
 }
 
@@ -264,15 +262,12 @@
 	int freq;
 	struct wpabuf *ies;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Starting short listen state (state=%s)",
+	p2p_dbg(p2p, "Starting short listen state (state=%s)",
 		p2p_state_txt(p2p->state));
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-				   p2p->cfg->channel);
+	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
 	if (freq < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown regulatory class/channel");
+		p2p_dbg(p2p, "Unknown regulatory class/channel");
 		return;
 	}
 
@@ -287,8 +282,7 @@
 		tu = p2p->cfg->max_listen * 1000 / 1024;
 
 	if (tu == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state "
-			"since duration was 0 TU");
+		p2p_dbg(p2p, "Skip listen state since duration was 0 TU");
 		p2p_set_timeout(p2p, 0, 0);
 		return;
 	}
@@ -303,8 +297,7 @@
 
 	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,
 		    ies) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to start listen mode");
+		p2p_dbg(p2p, "Failed to start listen mode");
 		p2p->pending_listen_freq = 0;
 	}
 	wpabuf_free(ies);
@@ -316,14 +309,11 @@
 	int freq;
 	struct wpabuf *ies;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Going to listen(only) state");
+	p2p_dbg(p2p, "Going to listen(only) state");
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-				   p2p->cfg->channel);
+	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
 	if (freq < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown regulatory class/channel");
+		p2p_dbg(p2p, "Unknown regulatory class/channel");
 		return -1;
 	}
 
@@ -333,13 +323,10 @@
 
 	if (p2p->p2p_scan_running) {
 		if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: p2p_scan running - connect is already "
-				"pending - skip listen");
+			p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen");
 			return 0;
 		}
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: p2p_scan running - delay start of listen state");
+		p2p_dbg(p2p, "p2p_scan running - delay start of listen state");
 		p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
 		return 0;
 	}
@@ -349,8 +336,7 @@
 		return -1;
 
 	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to start listen mode");
+		p2p_dbg(p2p, "Failed to start listen mode");
 		p2p->pending_listen_freq = 0;
 		wpabuf_free(ies);
 		return -1;
@@ -432,9 +418,7 @@
 			oldest = dev;
 	}
 	if (count + 1 > p2p->cfg->max_peers && oldest) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Remove oldest peer entry to make room for a new "
-			"peer");
+		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)
@@ -548,8 +532,8 @@
 }
 
 
-static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
-			      const struct p2p_message *msg)
+static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
+			      int probe_req, const struct p2p_message *msg)
 {
 	os_memcpy(dev->info.device_name, msg->device_name,
 		  sizeof(dev->info.device_name));
@@ -624,11 +608,11 @@
 			msg->config_methods : msg->wps_config_methods;
 		if (new_config_methods &&
 		    dev->info.config_methods != new_config_methods) {
-			wpa_printf(MSG_DEBUG, "P2P: Update peer " MACSTR
-				   " config_methods 0x%x -> 0x%x",
-				   MAC2STR(dev->info.p2p_device_addr),
-				   dev->info.config_methods,
-				   new_config_methods);
+			p2p_dbg(p2p, "Update peer " MACSTR
+				" config_methods 0x%x -> 0x%x",
+				MAC2STR(dev->info.p2p_device_addr),
+				dev->info.config_methods,
+				new_config_methods);
 			dev->info.config_methods = new_config_methods;
 		}
 	}
@@ -665,8 +649,7 @@
 
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ies, ies_len, &msg)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to parse P2P IE for a device entry");
+		p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
 		p2p_parse_free(&msg);
 		return -1;
 	}
@@ -676,18 +659,15 @@
 	else if (msg.device_id)
 		p2p_dev_addr = msg.device_id;
 	else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore scan data without P2P Device Info or "
-			"P2P Device Id");
+		p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
 		p2p_parse_free(&msg);
 		return -1;
 	}
 
 	if (!is_zero_ether_addr(p2p->peer_filter) &&
 	    os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
-			"filter for " MACSTR " due to peer filter",
-			MAC2STR(p2p_dev_addr));
+		p2p_dbg(p2p, "Do not add peer filter for " MACSTR
+			" due to peer filter", MAC2STR(p2p_dev_addr));
 		p2p_parse_free(&msg);
 		return 0;
 	}
@@ -709,9 +689,7 @@
 	 */
 	if (dev->last_seen.sec > 0 &&
 	    os_time_before(rx_time, &dev->last_seen)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not update peer "
-			"entry based on old frame (rx_time=%u.%06u "
-			"last_seen=%u.%06u)",
+		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,
 			(unsigned int) dev->last_seen.sec,
@@ -742,18 +720,15 @@
 		else
 			ds_freq = 2407 + *msg.ds_params * 5;
 		if (freq != ds_freq) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Update Listen frequency based on DS "
-				"Parameter Set IE: %d -> %d MHz",
+			p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz",
 				freq, ds_freq);
 			freq = ds_freq;
 		}
 	}
 
 	if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Update Listen frequency based on scan "
-			"results (" MACSTR " %d -> %d MHz (DS param %d)",
+		p2p_dbg(p2p, "Update Listen frequency based on scan results ("
+			MACSTR " %d -> %d MHz (DS param %d)",
 			MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
 			freq, msg.ds_params ? *msg.ds_params : -1);
 	}
@@ -764,7 +739,7 @@
 	}
 	dev->info.level = level;
 
-	p2p_copy_wps_info(dev, 0, &msg);
+	p2p_copy_wps_info(p2p, dev, 0, &msg);
 
 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
 		wpabuf_free(dev->info.wps_vendor_ext[i]);
@@ -798,13 +773,11 @@
 	if (dev->flags & P2P_DEV_REPORTED)
 		return 0;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Peer found with Listen frequency %d MHz "
-		"(rx_time=%u.%06u)", freq, (unsigned int) rx_time->sec,
+	p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
+		freq, (unsigned int) rx_time->sec,
 		(unsigned int) rx_time->usec);
 	if (dev->flags & P2P_DEV_USER_REJECTED) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Do not report rejected device");
+		p2p_dbg(p2p, "Do not report rejected device");
 		return 0;
 	}
 
@@ -824,9 +797,8 @@
 		 * Probe Response frame that includes the config_methods
 		 * information.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Do not report peer " MACSTR " with unknown "
-			"config methods", MAC2STR(addr));
+		p2p_dbg(p2p, "Do not report peer " MACSTR
+			" with unknown config methods", MAC2STR(addr));
 		return 0;
 	}
 
@@ -914,9 +886,8 @@
 		channel = c->reg_class[cl].channel[ch];
 	}
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
-		"channel: reg_class %u channel %u -> %d MHz",
+	freq = p2p_channel_to_freq(reg_class, channel);
+	p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz",
 		reg_class, channel, freq);
 	p2p->last_prog_scan_class = reg_class;
 	p2p->last_prog_scan_chan = channel;
@@ -935,9 +906,7 @@
 	int res;
 
 	if (p2p->drv_in_listen) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
-			"in Listen state - wait for it to end before "
-			"continuing");
+		p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing");
 		return;
 	}
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -945,27 +914,23 @@
 	if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
 	    (freq = p2p_get_next_prog_freq(p2p)) > 0) {
 		type = P2P_SCAN_SOCIAL_PLUS_ONE;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-			"(+ freq %u)", freq);
+		p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
 	} else {
 		type = P2P_SCAN_SOCIAL;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
+		p2p_dbg(p2p, "Starting search");
 	}
 
 	res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
 				 p2p->num_req_dev_types, p2p->req_dev_types,
 				 p2p->find_dev_id, pw_id);
 	if (res < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Scan request failed");
+		p2p_dbg(p2p, "Scan request failed");
 		p2p_continue_find(p2p);
 	} else if (res == 1) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
-			"p2p_scan at this point - will try again after "
-			"previous scan completes");
+		p2p_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 {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
+		p2p_dbg(p2p, "Running p2p_scan");
 		p2p->p2p_scan_running = 1;
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
@@ -977,7 +942,7 @@
 static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct p2p_data *p2p = eloop_ctx;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Find timeout -> stop");
+	p2p_dbg(p2p, "Find timeout -> stop");
 	p2p_stop_find(p2p);
 }
 
@@ -988,10 +953,8 @@
 	enum p2p_after_scan op;
 
 	if (p2p->after_scan_tx) {
-		/* TODO: schedule p2p_run_after_scan to be called from TX
-		 * status callback(?) */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
-			"Action frame at p2p_scan completion");
+		p2p->after_scan_tx_in_progress = 1;
+		p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion");
 		p2p->cfg->send_action(p2p->cfg->cb_ctx,
 				      p2p->after_scan_tx->freq,
 				      p2p->after_scan_tx->dst,
@@ -1019,19 +982,16 @@
 	case P2P_AFTER_SCAN_NOTHING:
 		break;
 	case P2P_AFTER_SCAN_LISTEN:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
-			"requested Listen state");
+		p2p_dbg(p2p, "Start previously requested Listen state");
 		p2p_listen(p2p, p2p->pending_listen_sec * 1000 +
 			   p2p->pending_listen_usec / 1000);
 		return 1;
 	case P2P_AFTER_SCAN_CONNECT:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
-			"requested connect with " MACSTR,
+		p2p_dbg(p2p, "Start previously requested connect with " MACSTR,
 			MAC2STR(p2p->after_scan_peer));
 		dev = p2p_get_device(p2p, p2p->after_scan_peer);
 		if (dev == NULL) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer not "
-				"known anymore");
+			p2p_dbg(p2p, "Peer not known anymore");
 			break;
 		}
 		p2p_connect_send(p2p, dev);
@@ -1046,8 +1006,7 @@
 {
 	struct p2p_data *p2p = eloop_ctx;
 	int running;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan timeout "
-		"(running=%d)", p2p->p2p_scan_running);
+	p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running);
 	running = p2p->p2p_scan_running;
 	/* Make sure we recover from missed scan results callback */
 	p2p->p2p_scan_running = 0;
@@ -1072,12 +1031,10 @@
 {
 	int res;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
-		type);
+	p2p_dbg(p2p, "Starting find (type=%d)", type);
 	os_get_time(&p2p->find_start);
 	if (p2p->p2p_scan_running) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
-			"already running");
+		p2p_dbg(p2p, "p2p_scan is already running");
 	}
 
 	p2p_free_req_dev_types(p2p);
@@ -1129,21 +1086,18 @@
 	}
 
 	if (res == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
+		p2p_dbg(p2p, "Running p2p_scan");
 		p2p->p2p_scan_running = 1;
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
 				       p2p, NULL);
 	} else if (res == 1) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
-			"p2p_scan at this point - will try again after "
-			"previous scan completes");
+		p2p_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 {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
-			"p2p_scan");
+		p2p_dbg(p2p, "Failed to start p2p_scan");
 		p2p_set_state(p2p, P2P_IDLE);
 		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	}
@@ -1173,12 +1127,11 @@
 	}
 	if (p2p->state != P2P_SEARCH_WHEN_READY)
 		return 0;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
-		"now that previous scan was completed");
+	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) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
 		return 0;
 	}
 	return 1;
@@ -1187,13 +1140,13 @@
 
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
+	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)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
 	p2p_set_state(p2p, P2P_IDLE);
 	p2p_free_req_dev_types(p2p);
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
@@ -1209,8 +1162,7 @@
 void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
 {
 	if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
-			"since we are on correct channel for response");
+		p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
 		return;
 	}
 	if (p2p->in_listen) {
@@ -1223,8 +1175,7 @@
 		 * when the operation gets canceled, so clear the internal
 		 * variable that is tracking driver state.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
-			"drv_in_listen (%d)", p2p->drv_in_listen);
+		p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen);
 		p2p->drv_in_listen = 0;
 	}
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -1244,17 +1195,14 @@
 	u8 op_class, op_channel;
 	unsigned int freq = force_freq ? force_freq : pref_freq;
 
-	if (p2p_freq_to_channel(p2p->cfg->country, freq,
-				&op_class, &op_channel) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported frequency %u MHz", freq);
+	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)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Frequency %u MHz (oper_class %u channel %u) not "
-			"allowed for P2P", freq, 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;
 	}
 
@@ -1281,26 +1229,23 @@
 
 	if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
 	    p2p_supported_freq(p2p, p2p->best_freq_overall) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
-				&op_class, &op_channel) == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
-			"overall channel as operating channel preference");
+	    p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+	    == 0) {
+		p2p_dbg(p2p, "Select best overall channel as operating channel preference");
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
 	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
 		   p2p_supported_freq(p2p, p2p->best_freq_5) &&
-		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
-				       &op_class, &op_channel) == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
-			"channel as operating channel preference");
+		   p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+		   == 0) {
+		p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference");
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
 	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
 		   p2p_supported_freq(p2p, p2p->best_freq_24) &&
-		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
-				       &op_class, &op_channel) == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
-			"GHz channel as operating channel preference");
+		   p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+				       &op_channel) == 0) {
+		p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
 	} else {
@@ -1335,9 +1280,7 @@
 	} else {
 		p2p_prepare_channel_best(p2p);
 	}
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Own preference for operation channel: "
-		"Operating Class %u Channel %u%s",
+	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
 		p2p->op_reg_class, p2p->op_channel,
 		force_freq ? " (forced)" : "");
 
@@ -1379,8 +1322,7 @@
 {
 	struct p2p_device *dev;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Request to start group negotiation - peer=" MACSTR
+	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",
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
@@ -1388,8 +1330,7 @@
 
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Cannot connect to unknown P2P Device " MACSTR,
+		p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
 			MAC2STR(peer_addr));
 		return -1;
 	}
@@ -1400,15 +1341,13 @@
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
 		if (!(dev->info.dev_capab &
 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Cannot connect to P2P Device " MACSTR
+			p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
 				" that is in a group and is not discoverable",
 				MAC2STR(peer_addr));
 			return -1;
 		}
 		if (dev->oper_freq <= 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Cannot connect to P2P Device " MACSTR
+			p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
 				" with incomplete information",
 				MAC2STR(peer_addr));
 			return -1;
@@ -1464,9 +1403,7 @@
 		 * new GO Negotiation, e.g., when the pending frame was from a
 		 * previous attempt at starting a GO Negotiation.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
-			"previous pending Action frame TX that was waiting "
-			"for p2p_scan completion");
+		p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
 		os_free(p2p->after_scan_tx);
 		p2p->after_scan_tx = NULL;
 	}
@@ -1475,8 +1412,7 @@
 	dev->status = P2P_SC_SUCCESS;
 
 	if (p2p->p2p_scan_running) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: p2p_scan running - delay connect send");
+		p2p_dbg(p2p, "p2p_scan running - delay connect send");
 		p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
 		os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
 		return 0;
@@ -1496,8 +1432,7 @@
 {
 	struct p2p_device *dev;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Request to authorize group negotiation - peer=" MACSTR
+	p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
 		"  GO Intent=%d  Intended Interface Address=" MACSTR
 		" wps_method=%d  persistent_group=%d",
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
@@ -1505,8 +1440,7 @@
 
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Cannot authorize unknown P2P Device " MACSTR,
+		p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR,
 			MAC2STR(peer_addr));
 		return -1;
 	}
@@ -1543,16 +1477,14 @@
 {
 	os_get_time(&dev->last_seen);
 
-	p2p_copy_wps_info(dev, 0, msg);
+	p2p_copy_wps_info(p2p, dev, 0, msg);
 
 	if (msg->listen_channel) {
 		int freq;
-		freq = p2p_channel_to_freq((char *) msg->listen_channel,
-					   msg->listen_channel[3],
+		freq = p2p_channel_to_freq(msg->listen_channel[3],
 					   msg->listen_channel[4]);
 		if (freq < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unknown peer Listen channel: "
+			p2p_dbg(p2p, "Unknown peer Listen channel: "
 				"country=%c%c(0x%02x) reg_class=%u channel=%u",
 				msg->listen_channel[0],
 				msg->listen_channel[1],
@@ -1560,8 +1492,8 @@
 				msg->listen_channel[3],
 				msg->listen_channel[4]);
 		} else {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update "
-				"peer " MACSTR " Listen channel: %u -> %u MHz",
+			p2p_dbg(p2p, "Update peer " MACSTR
+				" Listen channel: %u -> %u MHz",
 				MAC2STR(dev->info.p2p_device_addr),
 				dev->listen_freq, freq);
 			dev->listen_freq = freq;
@@ -1575,12 +1507,9 @@
 
 	if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
 		dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Completed device entry based on data from "
-			"GO Negotiation Request");
+		p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request");
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Created device entry based on GO Neg Req: "
+		p2p_dbg(p2p, "Created device entry based on GO Neg Req: "
 			MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' "
 			"listen_freq=%d",
 			MAC2STR(dev->info.p2p_device_addr),
@@ -1591,8 +1520,7 @@
 	dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY;
 
 	if (dev->flags & P2P_DEV_USER_REJECTED) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Do not report rejected device");
+		p2p_dbg(p2p, "Do not report rejected device");
 		return;
 	}
 
@@ -1628,10 +1556,8 @@
 	int freqs;
 	size_t i, j;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation with " MACSTR " completed (%s will be "
-		"GO)", MAC2STR(peer->info.p2p_device_addr),
-		go ? "local end" : "peer");
+	p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
+		MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
 
 	os_memset(&res, 0, sizeof(res));
 	res.role_go = go;
@@ -1647,8 +1573,7 @@
 
 	if (go) {
 		/* Setup AP mode for WPS provisioning */
-		res.freq = p2p_channel_to_freq(p2p->cfg->country,
-					       p2p->op_reg_class,
+		res.freq = p2p_channel_to_freq(p2p->op_reg_class,
 					       p2p->op_channel);
 		os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
 		res.ssid_len = p2p->ssid_len;
@@ -1672,8 +1597,7 @@
 			int freq;
 			if (freqs + 1 == P2P_MAX_CHANNELS)
 				break;
-			freq = p2p_channel_to_freq(peer->country, c->reg_class,
-						   c->channel[j]);
+			freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
 			if (freq < 0)
 				continue;
 			res.freq_list[freqs++] = freq;
@@ -1695,8 +1619,7 @@
 static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
 			      const u8 *data, size_t len, int rx_freq)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: RX P2P Public Action from " MACSTR, MAC2STR(sa));
+	p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa));
 	wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
 
 	if (len < 1)
@@ -1732,8 +1655,7 @@
 		p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1);
 		break;
 	default:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported P2P Public Action frame type %d",
+		p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d",
 			data[0]);
 		break;
 	}
@@ -1808,16 +1730,14 @@
 	len--;
 
 	/* P2P action frame */
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: RX P2P Action from " MACSTR, MAC2STR(sa));
+	p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
 	wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len);
 
 	if (len < 1)
 		return;
 	switch (data[0]) {
 	case P2P_NOA:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Received P2P Action - Notice of Absence");
+		p2p_dbg(p2p, "Received P2P Action - Notice of Absence");
 		/* TODO */
 		break;
 	case P2P_PRESENCE_REQ:
@@ -1830,8 +1750,7 @@
 		p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq);
 		break;
 	default:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Received P2P Action - unknown type %u", data[0]);
+		p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]);
 		break;
 	}
 }
@@ -1903,12 +1822,11 @@
 
 	if (msg.listen_channel) {
 		os_memcpy(dev->country, msg.listen_channel, 3);
-		dev->listen_freq = p2p_channel_to_freq(dev->country,
-						       msg.listen_channel[3],
+		dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
 						       msg.listen_channel[4]);
 	}
 
-	p2p_copy_wps_info(dev, 1, &msg);
+	p2p_copy_wps_info(p2p, dev, 1, &msg);
 
 	if (msg.wfd_subelems) {
 		wpabuf_free(dev->info.wfd_subelems);
@@ -1917,8 +1835,7 @@
 
 	p2p_parse_free(&msg);
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Created device entry based on Probe Req: " MACSTR
+	p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR
 		" dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d",
 		MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
 		dev->info.group_capab, dev->info.device_name,
@@ -2050,39 +1967,6 @@
 }
 
 
-static int is_11b(u8 rate)
-{
-	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
-}
-
-
-static int supp_rates_11b_only(struct ieee802_11_elems *elems)
-{
-	int num_11b = 0, num_others = 0;
-	int i;
-
-	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
-		return 0;
-
-	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
-		if (is_11b(elems->supp_rates[i]))
-			num_11b++;
-		else
-			num_others++;
-	}
-
-	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
-	     i++) {
-		if (is_11b(elems->ext_supp_rates[i]))
-			num_11b++;
-		else
-			num_others++;
-	}
-
-	return num_11b > 0 && num_others == 0;
-}
-
-
 static enum p2p_probe_req_status
 p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
 		const u8 *bssid, const u8 *ie, size_t ie_len)
@@ -2160,8 +2044,7 @@
 		return P2P_PREQ_NOT_PROCESSED;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Reply to P2P Probe Request in Listen state");
+	p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state");
 
 	/*
 	 * We do not really have a specific BSS that this frame is advertising,
@@ -2240,9 +2123,7 @@
 	    == 0 &&
 	    !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
 		/* Received a Probe Request from GO Negotiation peer */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Found GO Negotiation peer - try to start GO "
-			"negotiation from timeout");
+		p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
 		eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
 		eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
 		return P2P_PREQ_PROCESSED;
@@ -2253,9 +2134,7 @@
 	    os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
 	    == 0) {
 		/* Received a Probe Request from Invite peer */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Found Invite peer - try to start Invite from "
-			"timeout");
+		p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
 		eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
 		return P2P_PREQ_PROCESSED;
 	}
@@ -2430,24 +2309,20 @@
 void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
 {
 	if (p2p->go_neg_peer == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No pending Group Formation - "
-			"ignore WPS registration success notification");
+		p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification");
 		return; /* No pending Group Formation */
 	}
 
 	if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) !=
 	    0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore WPS registration success notification "
-			"for " MACSTR " (GO Negotiation peer " MACSTR ")",
+		p2p_dbg(p2p, "Ignore WPS registration success notification for "
+			MACSTR " (GO Negotiation peer " MACSTR ")",
 			MAC2STR(mac_addr),
 			MAC2STR(p2p->go_neg_peer->intended_addr));
 		return; /* Ignore unexpected peer address */
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Group Formation completed successfully with " MACSTR,
+	p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR,
 		MAC2STR(mac_addr));
 
 	p2p_clear_go_neg(p2p);
@@ -2457,14 +2332,11 @@
 void p2p_group_formation_failed(struct p2p_data *p2p)
 {
 	if (p2p->go_neg_peer == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No pending Group Formation - "
-			"ignore group formation failure notification");
+		p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification");
 		return; /* No pending Group Formation */
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Group Formation failed with " MACSTR,
+	p2p_dbg(p2p, "Group Formation failed with " MACSTR,
 		MAC2STR(p2p->go_neg_peer->intended_addr));
 
 	p2p_clear_go_neg(p2p);
@@ -2601,8 +2473,7 @@
 	if (dev == NULL)
 		return -1;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR,
-		MAC2STR(addr));
+	p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
 
 	if (p2p->go_neg_peer == dev)
 		p2p->go_neg_peer = NULL;
@@ -2803,8 +2674,7 @@
 				break;
 		} else if (dev->req_config_methods &&
 			   !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-				"pending Provision Discovery Request to "
+			p2p_dbg(p2p, "Send pending Provision Discovery Request to "
 				MACSTR " (config methods 0x%x)",
 				MAC2STR(dev->info.p2p_device_addr),
 				dev->req_config_methods);
@@ -2819,8 +2689,7 @@
 
 static void p2p_sd_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Service Discovery Query TX callback: success=%d",
+	p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d",
 		success);
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
@@ -2834,8 +2703,7 @@
 	}
 
 	if (p2p->sd_peer == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No SD peer entry known");
+		p2p_dbg(p2p, "No SD peer entry known");
 		p2p_continue_find(p2p);
 		return;
 	}
@@ -2869,8 +2737,7 @@
 		if (!dev->req_config_methods)
 			continue;
 
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-			"pending Provision Discovery Request to "
+		p2p_dbg(p2p, "Send pending Provision Discovery Request to "
 			MACSTR " (config methods 0x%x)",
 			MAC2STR(dev->info.p2p_device_addr),
 			dev->req_config_methods);
@@ -2883,8 +2750,7 @@
 
 static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Provision Discovery Request TX callback: success=%d",
+	p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d",
 		success);
 
 	/*
@@ -2951,8 +2817,8 @@
 		 * that have based on frames received after the last p2p_find
 		 * operation was started.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore old scan "
-			"result for " MACSTR " (rx_time=%u.%06u)",
+		p2p_dbg(p2p, "Ignore old scan result for " MACSTR
+			" (rx_time=%u.%06u)",
 			MAC2STR(bssid), (unsigned int) rx_time->sec,
 			(unsigned int) rx_time->usec);
 		return 0;
@@ -2967,8 +2833,7 @@
 void p2p_scan_res_handled(struct p2p_data *p2p)
 {
 	if (!p2p->p2p_scan_running) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan was not "
-			"running, but scan results received");
+		p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
 	}
 	p2p->p2p_scan_running = 0;
 	eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -3030,13 +2895,10 @@
 	struct p2p_device *dev = p2p->go_neg_peer;
 	int timeout;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation Request TX callback: success=%d",
-		success);
+	p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success);
 
 	if (dev == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No pending GO Negotiation");
+		p2p_dbg(p2p, "No pending GO Negotiation");
 		return;
 	}
 
@@ -3053,9 +2915,7 @@
 	if (!success &&
 	    (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
 	    !is_zero_ether_addr(dev->member_in_go_dev)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Peer " MACSTR " did not acknowledge request - "
-			"try to use device discoverability through its GO",
+		p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO",
 			MAC2STR(dev->info.p2p_device_addr));
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_send_dev_disc_req(p2p, dev);
@@ -3086,13 +2946,10 @@
 
 static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation Response TX callback: success=%d",
+	p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d",
 		success);
 	if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore TX callback event - GO Negotiation is "
-			"not running anymore");
+		p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore");
 		return;
 	}
 	p2p_set_state(p2p, P2P_CONNECT);
@@ -3100,14 +2957,19 @@
 }
 
 
-static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
+				       const u8 *addr)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation Response (failure) TX callback: "
-		"success=%d", success);
+	p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
 	if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer,
 				  p2p->go_neg_peer->status);
+	} else if (success) {
+		struct p2p_device *dev;
+		dev = p2p_get_device(p2p, addr);
+		if (dev &&
+		    dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
 	}
 }
 
@@ -3117,9 +2979,7 @@
 {
 	struct p2p_device *dev;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation Confirm TX callback: result=%d",
-		result);
+	p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	if (result == P2P_SEND_ACTION_FAILED) {
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
@@ -3136,10 +2996,7 @@
 		 * peer did indeed receive the frame, continue regardless of
 		 * the TX status.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Assume GO Negotiation Confirm TX was actually "
-			"received by the peer even though Ack was not "
-			"reported");
+		p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
 	}
 
 	dev = p2p->go_neg_peer;
@@ -3157,8 +3014,7 @@
 	enum p2p_pending_action_state state;
 	int success;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Action frame TX callback (state=%d freq=%u dst=" MACSTR
+	p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
 		" src=" MACSTR " bssid=" MACSTR " result=%d",
 		p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
 		MAC2STR(bssid), result);
@@ -3167,6 +3023,16 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	switch (state) {
 	case P2P_NO_PENDING_ACTION:
+		if (p2p->after_scan_tx_in_progress) {
+			p2p->after_scan_tx_in_progress = 0;
+			if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
+			    p2p_run_after_scan(p2p))
+				break;
+			if (p2p->state == P2P_SEARCH) {
+				p2p_dbg(p2p, "Continue find after after_scan_tx completion");
+				p2p_continue_find(p2p);
+			}
+		}
 		break;
 	case P2P_PENDING_GO_NEG_REQUEST:
 		p2p_go_neg_req_cb(p2p, success);
@@ -3175,7 +3041,7 @@
 		p2p_go_neg_resp_cb(p2p, success);
 		break;
 	case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
-		p2p_go_neg_resp_failure_cb(p2p, success);
+		p2p_go_neg_resp_failure_cb(p2p, success, dst);
 		break;
 	case P2P_PENDING_GO_NEG_CONFIRM:
 		p2p_go_neg_conf_cb(p2p, result);
@@ -3202,6 +3068,8 @@
 		p2p_go_disc_req_cb(p2p, success);
 		break;
 	}
+
+	p2p->after_scan_tx_in_progress = 0;
 }
 
 
@@ -3209,23 +3077,18 @@
 		   unsigned int duration)
 {
 	if (freq == p2p->pending_client_disc_freq) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Client discoverability remain-awake completed");
+		p2p_dbg(p2p, "Client discoverability remain-awake completed");
 		p2p->pending_client_disc_freq = 0;
 		return;
 	}
 
 	if (freq != p2p->pending_listen_freq) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected listen callback for freq=%u "
-			"duration=%u (pending_listen_freq=%u)",
+		p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)",
 			freq, duration, p2p->pending_listen_freq);
 		return;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Starting Listen timeout(%u,%u) on freq=%u based on "
-		"callback",
+	p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback",
 		p2p->pending_listen_sec, p2p->pending_listen_usec,
 		p2p->pending_listen_freq);
 	p2p->in_listen = 1;
@@ -3246,17 +3109,14 @@
 
 int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver ended Listen "
-		"state (freq=%u)", freq);
+	p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq);
 	p2p->drv_in_listen = 0;
 	if (p2p->in_listen)
 		return 0; /* Internal timeout will trigger the next step */
 
 	if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
 		if (p2p->go_neg_peer->connect_reqs >= 120) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Timeout on sending GO Negotiation "
-				"Request without getting response");
+			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
 			p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
 			return 0;
 		}
@@ -3274,9 +3134,7 @@
 			  * operation while in p2p_find. Avoid an attempt to
 			  * restart a scan here.
 			  */
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan "
-				"already in progress - do not try to start a "
-				"new one");
+			p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one");
 			return 1;
 		}
 		if (p2p->pending_listen_freq) {
@@ -3285,15 +3143,12 @@
 			 * offchannel operation for some reason. p2p_search()
 			 * will be started from internal timeout.
 			 */
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Listen "
-				"operation did not seem to start - delay "
-				"search phase to avoid busy loop");
+			p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop");
 			p2p_set_timeout(p2p, 0, 100000);
 			return 1;
 		}
 		if (p2p->search_delay) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
-				"search operation by %u ms",
+			p2p_dbg(p2p, "Delay search operation by %u ms",
 				p2p->search_delay);
 			p2p_set_timeout(p2p, p2p->search_delay / 1000,
 					(p2p->search_delay % 1000) * 1000);
@@ -3312,17 +3167,14 @@
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	if (p2p->go_neg_peer &&
 	    (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Wait for GO "
-			"Negotiation Confirm timed out - assume GO "
-			"Negotiation failed");
+		p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
 		return;
 	}
 	if (p2p->go_neg_peer &&
 	    (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
 	    p2p->go_neg_peer->connect_reqs < 120) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer expected to "
-			"wait our response - skip listen");
+		p2p_dbg(p2p, "Peer expected to wait our response - skip listen");
 		p2p_connect_send(p2p, p2p->go_neg_peer);
 		return;
 	}
@@ -3336,16 +3188,12 @@
 {
 	if (p2p->go_neg_peer) {
 		if (p2p->drv_in_listen) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is "
-				"still in Listen state; wait for it to "
-				"complete");
+			p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete");
 			return;
 		}
 
 		if (p2p->go_neg_peer->connect_reqs >= 120) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Timeout on sending GO Negotiation "
-				"Request without getting response");
+			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
 			p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
 			return;
 		}
@@ -3374,23 +3222,18 @@
 	struct p2p_device *dev = p2p->go_neg_peer;
 
 	if (dev == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown GO Neg peer - stop GO Neg wait");
+		p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
 		return;
 	}
 
 	dev->wait_count++;
 	if (dev->wait_count >= 120) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Timeout on waiting peer to become ready for GO "
-			"Negotiation");
+		p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation");
 		p2p_go_neg_failed(p2p, dev, -1);
 		return;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Go to Listen state while waiting for the peer to become "
-		"ready for GO Negotiation");
+	p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
 	p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
 	p2p_listen_in_find(p2p, 0);
 }
@@ -3398,8 +3241,7 @@
 
 static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Service Discovery Query timeout");
+	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;
@@ -3411,8 +3253,7 @@
 
 static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Provision Discovery Request timeout");
+	p2p_dbg(p2p, "Provision Discovery Request timeout");
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	p2p_continue_find(p2p);
 }
@@ -3430,8 +3271,7 @@
 	if (!p2p->user_initiated_pd)
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: User initiated Provision Discovery Request timeout");
+	p2p_dbg(p2p, "User initiated Provision Discovery Request timeout");
 
 	if (p2p->pd_retries) {
 		p2p->pd_retries--;
@@ -3469,8 +3309,7 @@
 		 * Better remain on operating channel instead of listen channel
 		 * when running a group.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Inviting in "
-			"active GO role - wait on operating channel");
+		p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
 		p2p_set_timeout(p2p, 0, 100000);
 		return;
 	}
@@ -3486,8 +3325,7 @@
 				p2p->invite_go_dev_addr);
 	} else {
 		if (p2p->invite_peer) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Invitation Request retry limit reached");
+			p2p_dbg(p2p, "Invitation Request retry limit reached");
 			if (p2p->cfg->invitation_result)
 				p2p->cfg->invitation_result(
 					p2p->cfg->cb_ctx, -1, NULL, NULL,
@@ -3502,8 +3340,7 @@
 {
 	struct p2p_data *p2p = eloop_ctx;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Timeout (state=%s)",
-		p2p_state_txt(p2p->state));
+	p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
 
 	p2p->in_listen = 0;
 
@@ -3518,8 +3355,7 @@
 		if (p2p->pending_action_state == P2P_PENDING_PD)
 			p2p_timeout_prov_disc_req(p2p);
 		if (p2p->search_delay && !p2p->in_search_delay) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
-				"search operation by %u ms",
+			p2p_dbg(p2p, "Delay search operation by %u ms",
 				p2p->search_delay);
 			p2p->in_search_delay = 1;
 			p2p_set_timeout(p2p, p2p->search_delay / 1000,
@@ -3543,9 +3379,7 @@
 			p2p_timeout_prov_disc_req(p2p);
 
 		if (p2p->ext_listen_only) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Extended Listen Timing - Listen State "
-				"completed");
+			p2p_dbg(p2p, "Extended Listen Timing - Listen State completed");
 			p2p->ext_listen_only = 0;
 			p2p_set_state(p2p, P2P_IDLE);
 		}
@@ -3583,11 +3417,10 @@
 	struct p2p_device *dev;
 
 	dev = p2p_get_device(p2p, peer_addr);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Local request to reject "
-		"connection attempts by peer " MACSTR, MAC2STR(peer_addr));
+	p2p_dbg(p2p, "Local request to reject connection attempts by peer "
+		MACSTR, MAC2STR(peer_addr));
 	if (dev == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
-			" unknown", MAC2STR(peer_addr));
+		p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr));
 		return -1;
 	}
 	dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -3788,12 +3621,10 @@
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
 {
 	if (enabled) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
-			"discoverability enabled");
+		p2p_dbg(p2p, "Client discoverability enabled");
 		p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
-			"discoverability disabled");
+		p2p_dbg(p2p, "Client discoverability disabled");
 		p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
 	}
 }
@@ -3842,9 +3673,9 @@
 {
 	struct wpabuf *req;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send Presence Request to "
-		"GO " MACSTR " (own interface " MACSTR ") freq=%u dur1=%u "
-		"int1=%u dur2=%u int2=%u",
+	p2p_dbg(p2p, "Send Presence Request to GO " MACSTR
+		" (own interface " MACSTR ") freq=%u dur1=%u int1=%u "
+		"dur2=%u int2=%u",
 		MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
 		freq, duration1, interval1, duration2, interval2);
 
@@ -3857,8 +3688,7 @@
 	if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr,
 			    go_interface_addr,
 			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 	wpabuf_free(req);
 
@@ -3904,8 +3734,7 @@
 	u8 noa[50];
 	int noa_len;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received P2P Action - P2P Presence Request");
+	p2p_dbg(p2p, "Received P2P Action - P2P Presence Request");
 
 	for (g = 0; g < p2p->num_groups; g++) {
 		if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]),
@@ -3915,23 +3744,20 @@
 		}
 	}
 	if (group == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore P2P Presence Request for unknown group "
+		p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group "
 			MACSTR, MAC2STR(da));
 		return;
 	}
 
 	if (p2p_parse(data, len, &msg) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to parse P2P Presence Request");
+		p2p_dbg(p2p, "Failed to parse P2P Presence Request");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 	parsed = 1;
 
 	if (msg.noa == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No NoA attribute in P2P Presence Request");
+		p2p_dbg(p2p, "No NoA attribute in P2P Presence Request");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
@@ -3955,8 +3781,7 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	if (p2p_send_action(p2p, rx_freq, sa, da, da,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 	wpabuf_free(resp);
 }
@@ -3967,33 +3792,27 @@
 {
 	struct p2p_message msg;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received P2P Action - P2P Presence Response");
+	p2p_dbg(p2p, "Received P2P Action - P2P Presence Response");
 
 	if (p2p_parse(data, len, &msg) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to parse P2P Presence Response");
+		p2p_dbg(p2p, "Failed to parse P2P Presence Response");
 		return;
 	}
 
 	if (msg.status == NULL || msg.noa == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Status or NoA attribute in P2P Presence "
-			"Response");
+		p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response");
 		p2p_parse_free(&msg);
 		return;
 	}
 
 	if (*msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: P2P Presence Request was rejected: status %u",
+		p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
 			*msg.status);
 		p2p_parse_free(&msg);
 		return;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: P2P Presence Request was accepted");
+	p2p_dbg(p2p, "P2P Presence Request was accepted");
 	wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
 		    msg.noa, msg.noa_len);
 	/* TODO: process NoA */
@@ -4019,25 +3838,20 @@
 		 * running at an inconvenient time. As a workaround, allow new
 		 * Extended Listen operation to be started.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Previous "
-			"Extended Listen operation had not been completed - "
-			"try again");
+		p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again");
 		p2p->ext_listen_only = 0;
 		p2p_set_state(p2p, P2P_IDLE);
 	}
 
 	if (p2p->state != P2P_IDLE) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip Extended "
-			"Listen timeout in active state (%s)",
-			p2p_state_txt(p2p->state));
+		p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state));
 		return;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Extended Listen timeout");
+	p2p_dbg(p2p, "Extended Listen timeout");
 	p2p->ext_listen_only = 1;
 	if (p2p_listen(p2p, p2p->ext_listen_period) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
-			"Listen state for Extended Listen Timing");
+		p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing");
 		p2p->ext_listen_only = 0;
 	}
 }
@@ -4048,25 +3862,22 @@
 {
 	if (period > 65535 || interval > 65535 || period > interval ||
 	    (period == 0 && interval > 0) || (period > 0 && interval == 0)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid Extended Listen Timing request: "
-			"period=%u interval=%u", period, interval);
+		p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u",
+			period, interval);
 		return -1;
 	}
 
 	eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
 
 	if (interval == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Disabling Extended Listen Timing");
+		p2p_dbg(p2p, "Disabling Extended Listen Timing");
 		p2p->ext_listen_period = 0;
 		p2p->ext_listen_interval = 0;
 		return 0;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Enabling Extended Listen Timing: period %u msec, "
-		"interval %u msec", period, interval);
+	p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec",
+		period, interval);
 	p2p->ext_listen_period = period;
 	p2p->ext_listen_interval = interval;
 	p2p->ext_listen_interval_sec = interval / 1000;
@@ -4094,8 +3905,7 @@
 	if (msg.minor_reason_code == NULL)
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-		"P2P: Deauthentication notification BSSID " MACSTR
+	p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
 		MAC2STR(bssid), reason_code, *msg.minor_reason_code);
 
@@ -4117,8 +3927,7 @@
 	if (msg.minor_reason_code == NULL)
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-		"P2P: Disassociation notification BSSID " MACSTR
+	p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
 		MAC2STR(bssid), reason_code, *msg.minor_reason_code);
 
@@ -4129,12 +3938,10 @@
 void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
 {
 	if (enabled) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
-			"Device operations enabled");
+		p2p_dbg(p2p, "Managed P2P Device operations enabled");
 		p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
-			"Device operations disabled");
+		p2p_dbg(p2p, "Managed P2P Device operations disabled");
 		p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
 	}
 }
@@ -4142,11 +3949,11 @@
 
 int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
 {
-	if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+	if (p2p_channel_to_freq(reg_class, channel) < 0)
 		return -1;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
-		"reg_class %u channel %u", reg_class, channel);
+	p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
+		reg_class, channel);
 	p2p->cfg->reg_class = reg_class;
 	p2p->cfg->channel = channel;
 
@@ -4156,7 +3963,7 @@
 
 int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
 {
-	wpa_hexdump_ascii(MSG_DEBUG, "P2P: New SSID postfix", postfix, len);
+	p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
 	if (postfix == NULL) {
 		p2p->cfg->ssid_postfix_len = 0;
 		return 0;
@@ -4172,12 +3979,11 @@
 int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 			 int cfg_op_channel)
 {
-	if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
-	    < 0)
+	if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
 		return -1;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
-		"reg_class %u channel %u", op_reg_class, op_channel);
+	p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u",
+		op_reg_class, op_channel);
 	p2p->cfg->op_reg_class = op_reg_class;
 	p2p->cfg->op_channel = op_channel;
 	p2p->cfg->cfg_op_channel = cfg_op_channel;
@@ -4233,18 +4039,16 @@
 {
 	os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
 	if (is_zero_ether_addr(p2p->peer_filter))
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Disable peer "
-			"filter");
+		p2p_dbg(p2p, "Disable peer filter");
 	else
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer "
-			"filter for " MACSTR, MAC2STR(p2p->peer_filter));
+		p2p_dbg(p2p, "Enable peer filter for " MACSTR,
+			MAC2STR(p2p->peer_filter));
 }
 
 
 void p2p_set_cross_connect(struct p2p_data *p2p, int enabled)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s",
-		enabled ? "enabled" : "disabled");
+	p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled");
 	if (p2p->cross_connect == enabled)
 		return;
 	p2p->cross_connect = enabled;
@@ -4265,7 +4069,7 @@
 
 void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Intra BSS distribution %s",
+	p2p_dbg(p2p, "Intra BSS distribution %s",
 		enabled ? "enabled" : "disabled");
 	p2p->cfg->p2p_intra_bss = enabled;
 }
@@ -4273,7 +4077,7 @@
 
 void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update channel list");
+	p2p_dbg(p2p, "Update channel list");
 	os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
 }
 
@@ -4283,11 +4087,9 @@
 		    size_t len, unsigned int wait_time)
 {
 	if (p2p->p2p_scan_running) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay Action "
-			"frame TX until p2p_scan completes");
+		p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
 		if (p2p->after_scan_tx) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
-				"previous pending Action frame TX");
+			p2p_dbg(p2p, "Dropped previous pending Action frame TX");
 			os_free(p2p->after_scan_tx);
 		}
 		p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
@@ -4312,8 +4114,8 @@
 void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
 			   int freq_overall)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d,"
-		"  5 GHz: %d,  overall: %d", freq_24, freq_5, freq_overall);
+	p2p_dbg(p2p, "Best channel: 2.4 GHz: %d,  5 GHz: %d,  overall: %d",
+		freq_24, freq_5, freq_overall);
 	p2p->best_freq_24 = freq_24;
 	p2p->best_freq_5 = freq_5;
 	p2p->best_freq_overall = freq_overall;
@@ -4322,8 +4124,7 @@
 
 void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own frequency preference: "
-		"%d MHz", freq);
+	p2p_dbg(p2p, "Own frequency preference: %d MHz", freq);
 	p2p->own_freq_preference = freq;
 }
 
@@ -4548,9 +4349,56 @@
 	p2p->min_disc_int = min_disc_int;
 	p2p->max_disc_int = max_disc_int;
 	p2p->max_disc_tu = max_disc_tu;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: "
-		"min=%d max=%d max_tu=%d", min_disc_int, max_disc_int,
-		max_disc_tu);
+	p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d",
+		min_disc_int, max_disc_int, max_disc_tu);
 
 	return 0;
 }
+
+
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[500];
+
+	if (!p2p->cfg->debug_print)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	buf[sizeof(buf) - 1] = '\0';
+	va_end(ap);
+	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf);
+}
+
+
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[500];
+
+	if (!p2p->cfg->debug_print)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	buf[sizeof(buf) - 1] = '\0';
+	va_end(ap);
+	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf);
+}
+
+
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[500];
+
+	if (!p2p->cfg->debug_print)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	buf[sizeof(buf) - 1] = '\0';
+	va_end(ap);
+	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 28a0a1d..c392d57 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -384,15 +384,18 @@
 #endif
 
 	/**
-	 * msg_ctx - Context to use with wpa_msg() calls
-	 */
-	void *msg_ctx;
-
-	/**
 	 * cb_ctx - Context to use with callback functions
 	 */
 	void *cb_ctx;
 
+	/**
+	 * debug_print - Debug print
+	 * @ctx: Callback context from cb_ctx
+	 * @level: Debug verbosity level (MSG_*)
+	 * @msg: Debug message
+	 */
+	void (*debug_print)(void *ctx, int level, const char *msg);
+
 
 	/* Callbacks to request lower layer driver operations */
 
@@ -558,6 +561,12 @@
 	void (*dev_lost)(void *ctx, const u8 *dev_addr);
 
 	/**
+	 * find_stopped - Notification of a p2p_find operation stopping
+	 * @ctx: Callback context from cb_ctx
+	 */
+	void (*find_stopped)(void *ctx);
+
+	/**
 	 * go_neg_req_rx - Notification of a receive GO Negotiation Request
 	 * @ctx: Callback context from cb_ctx
 	 * @src: Source address of the message triggering this notification
@@ -693,6 +702,7 @@
 	 * @persistent_group: Whether this is an invitation to reinvoke a
 	 *	persistent group (instead of invitation to join an active
 	 *	group)
+	 * @channels: Available operating channels for the group
 	 * Returns: Status code (P2P_SC_*)
 	 *
 	 * This optional callback can be used to implement persistent reconnect
@@ -713,7 +723,8 @@
 	u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
 				 const u8 *go_dev_addr, const u8 *ssid,
 				 size_t ssid_len, int *go, u8 *group_bssid,
-				 int *force_freq, int persistent_group);
+				 int *force_freq, int persistent_group,
+				 const struct p2p_channels *channels);
 
 	/**
 	 * invitation_received - Callback on Invitation Request RX
@@ -1648,6 +1659,15 @@
  */
 int p2p_supported_freq(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
+ * Returns: Preferred channel
+ */
+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);
 
 /**
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index c976b7c..76d01cf 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -42,8 +42,7 @@
 
 void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Device Discoverability Request TX callback: success=%d",
+	p2p_dbg(p2p, "Device Discoverability Request TX callback: success=%d",
 		success);
 
 	if (!success) {
@@ -56,9 +55,7 @@
 		return;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO acknowledged Device Discoverability Request - wait "
-		"for response");
+	p2p_dbg(p2p, "GO acknowledged Device Discoverability Request - wait for response");
 	/*
 	 * TODO: is the remain-on-channel from Action frame TX long enough for
 	 * most cases or should we try to increase its duration and/or start
@@ -74,9 +71,7 @@
 
 	go = p2p_get_device(p2p, dev->member_in_go_dev);
 	if (go == NULL || dev->oper_freq <= 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Could not find peer entry for GO and frequency "
-			"to send Device Discoverability Request");
+		p2p_dbg(p2p, "Could not find peer entry for GO and frequency to send Device Discoverability Request");
 		return -1;
 	}
 
@@ -84,8 +79,7 @@
 	if (req == NULL)
 		return -1;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending Device Discoverability Request to GO " MACSTR
+	p2p_dbg(p2p, "Sending Device Discoverability Request to GO " MACSTR
 		" for client " MACSTR,
 		MAC2STR(go->info.p2p_device_addr),
 		MAC2STR(dev->info.p2p_device_addr));
@@ -97,8 +91,7 @@
 	if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
 			    p2p->cfg->dev_addr, go->info.p2p_device_addr,
 			    wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		wpabuf_free(req);
 		/* TODO: how to recover from failure? */
 		return -1;
@@ -131,8 +124,7 @@
 
 void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Device Discoverability Response TX callback: success=%d",
+	p2p_dbg(p2p, "Device Discoverability Response TX callback: success=%d",
 		success);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 }
@@ -147,8 +139,7 @@
 	if (resp == NULL)
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending Device Discoverability Response to " MACSTR
+	p2p_dbg(p2p, "Sending Device Discoverability Response to " MACSTR
 		" (status %u freq %d)",
 		MAC2STR(addr), status, freq);
 
@@ -156,8 +147,7 @@
 	if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 
 	wpabuf_free(resp);
@@ -170,17 +160,14 @@
 	struct p2p_message msg;
 	size_t g;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Device Discoverability Request from " MACSTR
+	p2p_dbg(p2p, "Received Device Discoverability Request from " MACSTR
 		" (freq=%d)", MAC2STR(sa), rx_freq);
 
 	if (p2p_parse(data, len, &msg))
 		return;
 
 	if (msg.dialog_token == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid Dialog Token 0 (must be nonzero) in "
-			"Device Discoverability Request");
+		p2p_dbg(p2p, "Invalid Dialog Token 0 (must be nonzero) in Device Discoverability Request");
 		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
 				       P2P_SC_FAIL_INVALID_PARAMS);
 		p2p_parse_free(&msg);
@@ -188,9 +175,7 @@
 	}
 
 	if (msg.device_id == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: P2P Device ID attribute missing from Device "
-			"Discoverability Request");
+		p2p_dbg(p2p, "P2P Device ID attribute missing from Device Discoverability Request");
 		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
 				       P2P_SC_FAIL_INVALID_PARAMS);
 		p2p_parse_free(&msg);
@@ -200,9 +185,7 @@
 	for (g = 0; g < p2p->num_groups; g++) {
 		if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
 					  rx_freq) == 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
-				"GO Discoverability Request for the target "
-				"device");
+			p2p_dbg(p2p, "Scheduled GO Discoverability Request for the target device");
 			/*
 			 * P2P group code will use a callback to indicate TX
 			 * status, so that we can reply to the request once the
@@ -217,9 +200,7 @@
 		}
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
-		"was not found in any group or did not support client "
-		"discoverability");
+	p2p_dbg(p2p, "Requested client was not found in any group or did not support client discoverability");
 	p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
 			       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
 	p2p_parse_free(&msg);
@@ -233,15 +214,13 @@
 	struct p2p_device *go;
 	u8 status;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Device Discoverability Response from " MACSTR,
+	p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR,
 		MAC2STR(sa));
 
 	go = p2p->pending_client_disc_go;
 	if (go == NULL ||
 	    os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
-			"Device Discoverability Response");
+		p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response");
 		return;
 	}
 
@@ -254,9 +233,7 @@
 	}
 
 	if (msg.dialog_token != go->dialog_token) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
-			"Discoverability Response with unexpected dialog "
-			"token %u (expected %u)",
+		p2p_dbg(p2p, "Ignore Device Discoverability Response with unexpected dialog token %u (expected %u)",
 			msg.dialog_token, go->dialog_token);
 		p2p_parse_free(&msg);
 		return;
@@ -265,17 +242,14 @@
 	status = *msg.status;
 	p2p_parse_free(&msg);
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Device Discoverability Response status %u", status);
+	p2p_dbg(p2p, "Device Discoverability Response status %u", status);
 
 	if (p2p->go_neg_peer == NULL ||
 	    os_memcmp(p2p->pending_client_disc_addr,
 		      p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
 	    os_memcmp(p2p->go_neg_peer->member_in_go_dev,
 		      go->info.p2p_device_addr, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
-			"operation with the client discoverability peer "
-			"anymore");
+		p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore");
 		return;
 	}
 
@@ -284,8 +258,7 @@
 		 * Peer is expected to be awake for at least 100 TU; try to
 		 * connect immediately.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Client discoverability request succeeded");
+		p2p_dbg(p2p, "Client discoverability request succeeded");
 		if (p2p->state == P2P_CONNECT) {
 			/*
 			 * Change state to force the timeout to start in
@@ -301,8 +274,7 @@
 		 * Client discoverability request failed; try to connect from
 		 * timeout.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Client discoverability request failed");
+		p2p_dbg(p2p, "Client discoverability request failed");
 		p2p_set_timeout(p2p, 0, 500000);
 	}
 
@@ -311,14 +283,12 @@
 
 void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Discoverability Request TX callback: success=%d",
+	p2p_dbg(p2p, "GO Discoverability Request TX callback: success=%d",
 		success);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
 	if (p2p->pending_dev_disc_dialog_token == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
-			"Discoverability Request");
+		p2p_dbg(p2p, "No pending Device Discoverability Request");
 		return;
 	}
 
@@ -338,9 +308,7 @@
 	unsigned int tu;
 	struct wpabuf *ies;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GO Discoverability Request - remain awake for "
-		"100 TU");
+	p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
 
 	ies = p2p_build_probe_resp_ies(p2p);
 	if (ies == NULL)
@@ -351,9 +319,7 @@
 	tu = 100;
 	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
 		    ies) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to start listen mode for client "
-			"discoverability");
+		p2p_dbg(p2p, "Failed to start listen mode for client discoverability");
 	}
 	wpabuf_free(ies);
 }
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index c143ef4..4fba550 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -49,8 +49,7 @@
 	os_memcpy(dev->country, pos, 3);
 	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3);
 	if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-			"P2P: Mismatching country (ours=%c%c peer's=%c%c)",
+		p2p_info(p2p, "Mismatching country (ours=%c%c peer's=%c%c)",
 			p2p->cfg->country[0], p2p->cfg->country[1],
 			pos[0], pos[1]);
 		return -1;
@@ -61,8 +60,7 @@
 		struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
 		cl->reg_class = *pos++;
 		if (pos + 1 + pos[0] > end) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-				"P2P: Invalid peer Channel List");
+			p2p_info(p2p, "Invalid peer Channel List");
 			return -1;
 		}
 		channels = *pos++;
@@ -76,14 +74,12 @@
 	}
 
 	p2p_channels_intersect(own, &dev->channels, &intersection);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own reg_classes %d "
-		"peer reg_classes %d intersection reg_classes %d",
+	p2p_dbg(p2p, "Own reg_classes %d peer reg_classes %d intersection reg_classes %d",
 		(int) own->reg_classes,
 		(int) dev->channels.reg_classes,
 		(int) intersection.reg_classes);
 	if (intersection.reg_classes == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-			"P2P: No common channels found");
+		p2p_info(p2p, "No common channels found");
 		return -1;
 	}
 	return 0;
@@ -194,8 +190,7 @@
 
 	if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
 		u16 config_method;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Use PD-before-GO-Neg workaround for " MACSTR,
+		p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR,
 			MAC2STR(dev->info.p2p_device_addr));
 		if (dev->wps_method == WPS_PIN_DISPLAY)
 			config_method = WPS_CONFIG_KEYPAD;
@@ -211,9 +206,8 @@
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
 	if (freq <= 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Listen/Operating frequency known for the "
-			"peer " MACSTR " to send GO Negotiation Request",
+		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+			MACSTR " to send GO Negotiation Request",
 			MAC2STR(dev->info.p2p_device_addr));
 		return -1;
 	}
@@ -221,8 +215,7 @@
 	req = p2p_build_go_neg_req(p2p, dev);
 	if (req == NULL)
 		return -1;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending GO Negotiation Request");
+	p2p_dbg(p2p, "Sending GO Negotiation Request");
 	p2p_set_state(p2p, P2P_CONNECT);
 	p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
 	p2p->go_neg_peer = dev;
@@ -231,8 +224,7 @@
 	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), 500) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		/* Use P2P find to recover and retry */
 		p2p_set_timeout(p2p, 0, 0);
 	} else
@@ -254,8 +246,7 @@
 	u8 group_capab;
 	size_t extra = 0;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Building GO Negotiation Response");
+	p2p_dbg(p2p, "Building GO Negotiation Response");
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -289,8 +280,7 @@
 	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
 	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
 	if (peer && peer->go_state == REMOTE_GO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
-			"Channel attribute");
+		p2p_dbg(p2p, "Omit Operating Channel attribute");
 	} else {
 		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
 					      p2p->op_reg_class,
@@ -351,23 +341,21 @@
 	unsigned int i;
 
 	if (p2p->own_freq_preference > 0 &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->own_freq_preference,
+	    p2p_freq_to_channel(p2p->own_freq_preference,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick own channel "
-			"preference (reg_class %u channel %u) from "
-			"intersection", op_reg_class, op_channel);
+		p2p_dbg(p2p, "Pick own channel preference (reg_class %u channel %u) from intersection",
+			op_reg_class, op_channel);
 		p2p->op_reg_class = op_reg_class;
 		p2p->op_channel = op_channel;
 		return;
 	}
 
 	if (p2p->best_freq_overall > 0 &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+	    p2p_freq_to_channel(p2p->best_freq_overall,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best overall "
-			"channel (reg_class %u channel %u) from intersection",
+		p2p_dbg(p2p, "Pick best overall channel (reg_class %u channel %u) from intersection",
 			op_reg_class, op_channel);
 		p2p->op_reg_class = op_reg_class;
 		p2p->op_channel = op_channel;
@@ -375,16 +363,14 @@
 	}
 
 	/* First, try to pick the best channel from another band */
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
-				   p2p->op_channel);
+	freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
 	if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
 	    !p2p_channels_includes(intersection, p2p->op_reg_class,
 				   p2p->op_channel) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+	    p2p_freq_to_channel(p2p->best_freq_5,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
-			"channel (reg_class %u channel %u) from intersection",
+		p2p_dbg(p2p, "Pick best 5 GHz channel (reg_class %u channel %u) from intersection",
 			op_reg_class, op_channel);
 		p2p->op_reg_class = op_reg_class;
 		p2p->op_channel = op_channel;
@@ -394,11 +380,10 @@
 	if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
 	    !p2p_channels_includes(intersection, p2p->op_reg_class,
 				   p2p->op_channel) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+	    p2p_freq_to_channel(p2p->best_freq_24,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
-			"channel (reg_class %u channel %u) from intersection",
+		p2p_dbg(p2p, "Pick best 2.4 GHz channel (reg_class %u channel %u) from intersection",
 			op_reg_class, op_channel);
 		p2p->op_reg_class = op_reg_class;
 		p2p->op_channel = op_channel;
@@ -412,9 +397,7 @@
 					  p2p->cfg->pref_chan[i].chan)) {
 			p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
 			p2p->op_channel = p2p->cfg->pref_chan[i].chan;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
-				"highest preferred chnnel (op_class %u "
-				"channel %u) from intersection",
+			p2p_dbg(p2p, "Pick highest preferred channel (op_class %u channel %u) from intersection",
 				p2p->op_reg_class, p2p->op_channel);
 			return;
 		}
@@ -425,9 +408,7 @@
 		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) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Pick possible HT40 channel (reg_class "
-				"%u channel %u) from intersection",
+			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];
@@ -442,9 +423,7 @@
 	 */
 	if (p2p_channels_includes(intersection, p2p->op_reg_class,
 				  p2p->op_channel)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Using original operating class and channel "
-			"(op_class %u channel %u) from intersection",
+		p2p_dbg(p2p, "Using original operating class and channel (op_class %u channel %u) from intersection",
 			p2p->op_reg_class, p2p->op_channel);
 		return;
 	}
@@ -454,8 +433,7 @@
 	 * no better options seems to be available.
 	 */
 	cl = &intersection->reg_class[0];
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick another channel "
-		"(reg_class %u channel %u) from intersection",
+	p2p_dbg(p2p, "Pick another channel (reg_class %u channel %u) from intersection",
 		cl->reg_class, cl->channel[0]);
 	p2p->op_reg_class = cl->reg_class;
 	p2p->op_channel = cl->channel[0];
@@ -472,15 +450,14 @@
 	if (intersection.reg_classes == 0 ||
 	    intersection.reg_class[0].channels == 0) {
 		*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No common channels found");
+		p2p_dbg(p2p, "No common channels found");
 		return -1;
 	}
 
 	for (i = 0; i < intersection.reg_classes; i++) {
 		struct p2p_reg_class *c;
 		c = &intersection.reg_class[i];
-		wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
+		p2p_dbg(p2p, "reg_class %u", c->reg_class);
 		wpa_hexdump(MSG_DEBUG, "P2P: channels",
 			    c->channel, c->channels);
 	}
@@ -489,20 +466,16 @@
 				   p2p->op_channel)) {
 		if (dev->flags & P2P_DEV_FORCE_FREQ) {
 			*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
-				"not support the forced channel");
+			p2p_dbg(p2p, "Peer does not support the forced channel");
 			return -1;
 		}
 
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
-			"channel (op_class %u channel %u) not acceptable to "
-			"the peer", p2p->op_reg_class, p2p->op_channel);
+		p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer",
+			p2p->op_reg_class, p2p->op_channel);
 		p2p_reselect_channel(p2p, &intersection);
 	} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
 		   !p2p->cfg->cfg_op_channel) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
-			"channel selection with peer information received; "
-			"previously selected op_class %u channel %u",
+		p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u",
 			p2p->op_reg_class, p2p->op_channel);
 		p2p_reselect_channel(p2p, &intersection);
 	}
@@ -526,17 +499,14 @@
 	int tie_breaker = 0;
 	int freq;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GO Negotiation Request from " MACSTR
-		"(freq=%d)", MAC2STR(sa), rx_freq);
+	p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
+		MAC2STR(sa), rx_freq);
 
 	if (p2p_parse(data, len, &msg))
 		return;
 
 	if (!msg.capability) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Capability attribute missing from GO "
-			"Negotiation Request");
+		p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
 		goto fail;
 #endif /* CONFIG_P2P_STRICT */
@@ -545,53 +515,42 @@
 	if (msg.go_intent)
 		tie_breaker = *msg.go_intent & 0x01;
 	else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory GO Intent attribute missing from GO "
-			"Negotiation Request");
+		p2p_dbg(p2p, "Mandatory GO Intent attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
 		goto fail;
 #endif /* CONFIG_P2P_STRICT */
 	}
 
 	if (!msg.config_timeout) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Configuration Timeout attribute "
-			"missing from GO Negotiation Request");
+		p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Request");
 #ifdef CONFIG_P2P_STRICT
 		goto fail;
 #endif /* CONFIG_P2P_STRICT */
 	}
 
 	if (!msg.listen_channel) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Listen Channel attribute received");
+		p2p_dbg(p2p, "No Listen Channel attribute received");
 		goto fail;
 	}
 	if (!msg.operating_channel) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Operating Channel attribute received");
+		p2p_dbg(p2p, "No Operating Channel attribute received");
 		goto fail;
 	}
 	if (!msg.channel_list) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Channel List attribute received");
+		p2p_dbg(p2p, "No Channel List attribute received");
 		goto fail;
 	}
 	if (!msg.intended_addr) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Intended P2P Interface Address attribute "
-			"received");
+		p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
 		goto fail;
 	}
 	if (!msg.p2p_device_info) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No P2P Device Info attribute received");
+		p2p_dbg(p2p, "No P2P Device Info attribute received");
 		goto fail;
 	}
 
 	if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected GO Negotiation Request SA=" MACSTR
+		p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR
 			" != dev_addr=" MACSTR,
 			MAC2STR(sa), MAC2STR(msg.p2p_device_addr));
 		goto fail;
@@ -600,9 +559,8 @@
 	dev = p2p_get_device(p2p, sa);
 
 	if (msg.status && *msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected Status attribute (%d) in GO "
-			"Negotiation Request", *msg.status);
+		p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
+			*msg.status);
 		goto fail;
 	}
 
@@ -611,122 +569,96 @@
 	else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
 		p2p_add_dev_info(p2p, sa, dev, &msg);
 	if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: User has rejected this peer");
+		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) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Not ready for GO negotiation with " MACSTR,
+		p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
 			MAC2STR(sa));
 		status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
-		if (dev)
-			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
 		p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa,
 					msg.dev_password_id);
 	} else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Already in Group Formation with another peer");
+		p2p_dbg(p2p, "Already in Group Formation with another peer");
 		status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
 	} else {
 		int go;
 
 		if (!p2p->go_neg_peer) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting "
-				"GO Negotiation with previously authorized "
-				"peer");
+			p2p_dbg(p2p, "Starting GO Negotiation with previously authorized peer");
 			if (!(dev->flags & P2P_DEV_FORCE_FREQ)) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: Use default channel settings");
+				p2p_dbg(p2p, "Use default channel settings");
 				p2p->op_reg_class = p2p->cfg->op_reg_class;
 				p2p->op_channel = p2p->cfg->op_channel;
 				os_memcpy(&p2p->channels, &p2p->cfg->channels,
 					  sizeof(struct p2p_channels));
 			} else {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: Use previously configured "
-					"forced channel settings");
+				p2p_dbg(p2p, "Use previously configured forced channel settings");
 			}
 		}
 
 		dev->flags &= ~P2P_DEV_NOT_YET_READY;
 
 		if (!msg.go_intent) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: No GO Intent attribute received");
+			p2p_dbg(p2p, "No GO Intent attribute received");
 			goto fail;
 		}
 		if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Invalid GO Intent value (%u) received",
+			p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
 				*msg.go_intent >> 1);
 			goto fail;
 		}
 
 		if (dev->go_neg_req_sent &&
 		    os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Do not reply since peer has higher "
-				"address and GO Neg Request already sent");
+			p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
 			p2p_parse_free(&msg);
 			return;
 		}
 
 		go = p2p_go_det(p2p->go_intent, *msg.go_intent);
 		if (go < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Incompatible GO Intent");
+			p2p_dbg(p2p, "Incompatible GO Intent");
 			status = P2P_SC_FAIL_BOTH_GO_INTENT_15;
 			goto fail;
 		}
 
 		if (p2p_peer_channels(p2p, dev, msg.channel_list,
 				      msg.channel_list_len) < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: No common channels found");
+			p2p_dbg(p2p, "No common channels found");
 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 			goto fail;
 		}
 
 		switch (msg.dev_password_id) {
 		case DEV_PW_REGISTRAR_SPECIFIED:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: PIN from peer Display");
+			p2p_dbg(p2p, "PIN from peer Display");
 			if (dev->wps_method != WPS_PIN_KEYPAD) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: We have wps_method=%s -> "
-					"incompatible",
+				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;
 		case DEV_PW_USER_SPECIFIED:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Peer entered PIN on Keypad");
+			p2p_dbg(p2p, "Peer entered PIN on Keypad");
 			if (dev->wps_method != WPS_PIN_DISPLAY) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: We have wps_method=%s -> "
-					"incompatible",
+				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;
 		case DEV_PW_PUSHBUTTON:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Peer using pushbutton");
+			p2p_dbg(p2p, "Peer using pushbutton");
 			if (dev->wps_method != WPS_PBC) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: We have wps_method=%s -> "
-					"incompatible",
+				p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
 					p2p_wps_method_str(dev->wps_method));
 				status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
 				goto fail;
 			}
 			break;
 		default:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unsupported Device Password ID %d",
+			p2p_dbg(p2p, "Unsupported Device Password ID %d",
 				msg.dev_password_id);
 			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
 			goto fail;
@@ -736,20 +668,17 @@
 			goto fail;
 
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
-			"channel preference: %d MHz", dev->oper_freq);
+		p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+			dev->oper_freq);
 
 		if (msg.config_timeout) {
 			dev->go_timeout = msg.config_timeout[0];
 			dev->client_timeout = msg.config_timeout[1];
 		}
 
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
 		if (p2p->state != P2P_IDLE)
 			p2p_stop_find_for_freq(p2p, rx_freq);
 		p2p_set_state(p2p, P2P_GO_NEG);
@@ -768,17 +697,14 @@
 	p2p_parse_free(&msg);
 	if (resp == NULL)
 		return;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending GO Negotiation Response");
+	p2p_dbg(p2p, "Sending GO Negotiation Response");
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown regulatory class/channel");
+		p2p_dbg(p2p, "Unknown regulatory class/channel");
 		wpabuf_free(resp);
 		return;
 	}
@@ -802,8 +728,7 @@
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 
 	wpabuf_free(resp);
@@ -821,8 +746,7 @@
 	u8 group_capab;
 	size_t extra = 0;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Building GO Negotiation Confirm");
+	p2p_dbg(p2p, "Building GO Negotiation Confirm");
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -887,14 +811,12 @@
 	u8 status = P2P_SC_SUCCESS;
 	int freq;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GO Negotiation Response from " MACSTR
+	p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
 		" (freq=%d)", MAC2STR(sa), rx_freq);
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
 	    dev != p2p->go_neg_peer) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Not ready for GO negotiation with " MACSTR,
+		p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
 			MAC2STR(sa));
 		return;
 	}
@@ -903,44 +825,35 @@
 		return;
 
 	if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Was not expecting GO Negotiation Response - "
-			"ignore");
+		p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
 		p2p_parse_free(&msg);
 		return;
 	}
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
 
 	if (msg.dialog_token != dev->dialog_token) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected Dialog Token %u (expected %u)",
+		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
 			msg.dialog_token, dev->dialog_token);
 		p2p_parse_free(&msg);
 		return;
 	}
 
 	if (!msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Status attribute received");
+		p2p_dbg(p2p, "No Status attribute received");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 	if (*msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Negotiation rejected: status %d",
-			*msg.status);
+		p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
 		dev->go_neg_req_sent = 0;
 		if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Wait for the peer to become ready for "
-				"GO Negotiation");
+			p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
 			dev->flags |= P2P_DEV_NOT_YET_READY;
 			dev->wait_count = 0;
 			p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
 			p2p_set_timeout(p2p, 0, 0);
 		} else {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Stop GO Negotiation attempt");
+			p2p_dbg(p2p, "Stop GO Negotiation attempt");
 			p2p_go_neg_failed(p2p, dev, *msg.status);
 		}
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -949,9 +862,7 @@
 	}
 
 	if (!msg.capability) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Capability attribute missing from GO "
-			"Negotiation Response");
+		p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
@@ -959,9 +870,7 @@
 	}
 
 	if (!msg.p2p_device_info) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory P2P Device Info attribute missing "
-			"from GO Negotiation Response");
+		p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
@@ -969,22 +878,18 @@
 	}
 
 	if (!msg.intended_addr) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Intended P2P Interface Address attribute "
-			"received");
+		p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 
 	if (!msg.go_intent) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No GO Intent attribute received");
+		p2p_dbg(p2p, "No GO Intent attribute received");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 	if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid GO Intent value (%u) received",
+		p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
 			*msg.go_intent >> 1);
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
@@ -992,8 +897,7 @@
 
 	go = p2p_go_det(p2p->go_intent, *msg.go_intent);
 	if (go < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Incompatible GO Intent");
+		p2p_dbg(p2p, "Incompatible GO Intent");
 		status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
 		goto fail;
 	}
@@ -1003,18 +907,14 @@
 		p2p->ssid_len = msg.group_id_len - ETH_ALEN;
 		os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
 	} else if (!go) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory P2P Group ID attribute missing from "
-			"GO Negotiation Response");
+		p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response");
 		p2p->ssid_len = 0;
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 
 	if (!msg.config_timeout) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Configuration Timeout attribute "
-			"missing from GO Negotiation Response");
+		p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response");
 #ifdef CONFIG_P2P_STRICT
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
@@ -1029,76 +929,61 @@
 		 * Note: P2P Client may omit Operating Channel attribute to
 		 * indicate it does not have a preference.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Operating Channel attribute received");
+		p2p_dbg(p2p, "No Operating Channel attribute received");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 	if (!msg.channel_list) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Channel List attribute received");
+		p2p_dbg(p2p, "No Channel List attribute received");
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
 
 	if (p2p_peer_channels(p2p, dev, msg.channel_list,
 			      msg.channel_list_len) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No common channels found");
+		p2p_dbg(p2p, "No common channels found");
 		status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 		goto fail;
 	}
 
 	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
-			"channel preference: %d MHz", dev->oper_freq);
+		p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+			dev->oper_freq);
 	} else
 		dev->oper_freq = 0;
 
 	switch (msg.dev_password_id) {
 	case DEV_PW_REGISTRAR_SPECIFIED:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: PIN from peer Display");
+		p2p_dbg(p2p, "PIN from peer Display");
 		if (dev->wps_method != WPS_PIN_KEYPAD) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: We have wps_method=%s -> "
-				"incompatible",
+			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;
 	case DEV_PW_USER_SPECIFIED:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Peer entered PIN on Keypad");
+		p2p_dbg(p2p, "Peer entered PIN on Keypad");
 		if (dev->wps_method != WPS_PIN_DISPLAY) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: We have wps_method=%s -> "
-				"incompatible",
+			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;
 	case DEV_PW_PUSHBUTTON:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Peer using pushbutton");
+		p2p_dbg(p2p, "Peer using pushbutton");
 		if (dev->wps_method != WPS_PBC) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: We have wps_method=%s -> "
-				"incompatible",
+			p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
 				p2p_wps_method_str(dev->wps_method));
 			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
 			goto fail;
 		}
 		break;
 	default:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported Device Password ID %d",
+		p2p_dbg(p2p, "Unsupported Device Password ID %d",
 			msg.dev_password_id);
 		status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
 		goto fail;
@@ -1110,8 +995,7 @@
 	p2p_set_state(p2p, P2P_GO_NEG);
 	p2p_clear_timeout(p2p);
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+	p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
 	os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
 
 fail:
@@ -1120,8 +1004,7 @@
 	p2p_parse_free(&msg);
 	if (conf == NULL)
 		return;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending GO Negotiation Confirm");
+	p2p_dbg(p2p, "Sending GO Negotiation Confirm");
 	if (status == P2P_SC_SUCCESS) {
 		p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -1133,14 +1016,12 @@
 		freq = dev->listen_freq;
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
 			    wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		p2p_go_neg_failed(p2p, dev, -1);
 	}
 	wpabuf_free(conf);
 	if (status != P2P_SC_SUCCESS) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Negotiation failed");
+		p2p_dbg(p2p, "GO Negotiation failed");
 		p2p_go_neg_failed(p2p, dev, status);
 	}
 }
@@ -1152,22 +1033,18 @@
 	struct p2p_device *dev;
 	struct p2p_message msg;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GO Negotiation Confirm from " MACSTR,
+	p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
 		MAC2STR(sa));
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
 	    dev != p2p->go_neg_peer) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Not ready for GO negotiation with " MACSTR,
+		p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
 			MAC2STR(sa));
 		return;
 	}
 
 	if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopped waiting "
-			"for TX status on GO Negotiation Response since we "
-			"already received Confirmation");
+		p2p_dbg(p2p, "Stopped waiting for TX status on GO Negotiation Response since we already received Confirmation");
 		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	}
 
@@ -1175,31 +1052,25 @@
 		return;
 
 	if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Was not expecting GO Negotiation Confirm - "
-			"ignore");
+		p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
 		return;
 	}
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
 
 	if (msg.dialog_token != dev->dialog_token) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected Dialog Token %u (expected %u)",
+		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
 			msg.dialog_token, dev->dialog_token);
 		p2p_parse_free(&msg);
 		return;
 	}
 
 	if (!msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Status attribute received");
+		p2p_dbg(p2p, "No Status attribute received");
 		p2p_parse_free(&msg);
 		return;
 	}
 	if (*msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Negotiation rejected: status %d",
-			*msg.status);
+		p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
 		p2p_go_neg_failed(p2p, dev, *msg.status);
 		p2p_parse_free(&msg);
 		return;
@@ -1210,9 +1081,7 @@
 		p2p->ssid_len = msg.group_id_len - ETH_ALEN;
 		os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
 	} else if (dev->go_state == REMOTE_GO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory P2P Group ID attribute missing from "
-			"GO Negotiation Confirmation");
+		p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
 		p2p->ssid_len = 0;
 		p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
 		p2p_parse_free(&msg);
@@ -1220,9 +1089,7 @@
 	}
 
 	if (!msg.operating_channel) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Operating Channel attribute missing "
-			"from GO Negotiation Confirmation");
+		p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
 		p2p_parse_free(&msg);
 		return;
@@ -1231,20 +1098,16 @@
 
 #ifdef ANDROID_P2P
 	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
-			"channel preference: %d MHz", dev->oper_freq);
+		p2p_dbg(p2p, "P2P: Peer operating channel preference: %d MHz",
+			dev->oper_freq);
 	} else
 		dev->oper_freq = 0;
 #endif
 
 	if (!msg.channel_list) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Operating Channel attribute missing "
-			"from GO Negotiation Confirmation");
+		p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
 #ifdef CONFIG_P2P_STRICT
 		p2p_parse_free(&msg);
 		return;
@@ -1258,9 +1121,7 @@
 		 * This should not happen since GO negotiation has already
 		 * been completed.
 		 */
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected GO Neg state - do not know which end "
-			"becomes GO");
+		p2p_dbg(p2p, "Unexpected GO Neg state - do not know which end becomes GO");
 		return;
 	}
 
@@ -1272,8 +1133,7 @@
 	 * the group so that we will remain on the current channel to
 	 * acknowledge any possible retransmission from the peer.
 	 */
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: 20 ms wait on current "
-		"channel before starting group");
+	p2p_dbg(p2p, "20 ms wait on current channel before starting group");
 	os_sleep(0, 20000);
 
 	p2p_go_complete(p2p, dev);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 852ddf5..15e7622 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -378,8 +378,8 @@
 	} else {
 		WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
 			     2);
-		wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
-			   count);
+		p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors",
+			count);
 	}
 
 	wfd_ie = wifi_display_encaps(wfd_subelems);
@@ -588,7 +588,7 @@
 	m->next = group->members;
 	group->members = m;
 	group->num_members++;
-	wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
+	p2p_dbg(group->p2p,  "Add client " MACSTR
 		" to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
 		MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
 		m->client_info ? 1 : 0,
@@ -641,8 +641,8 @@
 void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
 {
 	if (p2p_group_remove_member(group, addr)) {
-		wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
-			"client " MACSTR " from group; num_members=%u/%u",
+		p2p_dbg(group->p2p, "Remove client " MACSTR
+			" from group; num_members=%u/%u",
 			MAC2STR(addr), group->num_members,
 			group->cfg->max_clients);
 		if (group->num_members == group->cfg->max_clients - 1)
@@ -854,20 +854,18 @@
 
 	m = p2p_group_get_client(group, dev_id);
 	if (m == NULL || m->client_info == NULL) {
-		wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
-			   "group " MACSTR,
-			   MAC2STR(group->cfg->interface_addr));
+		p2p_dbg(group->p2p, "Requested client was not in this group "
+			MACSTR, MAC2STR(group->cfg->interface_addr));
 		return -1;
 	}
 
 	if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-		wpa_printf(MSG_DEBUG, "P2P: Requested client does not support "
-			   "client discoverability");
+		p2p_dbg(group->p2p, "Requested client does not support client discoverability");
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be "
-		   "sent to " MACSTR, MAC2STR(dev_id));
+	p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to "
+		MACSTR, MAC2STR(dev_id));
 
 	req = p2p_build_go_disc_req();
 	if (req == NULL)
@@ -882,8 +880,7 @@
 				  group->cfg->interface_addr,
 				  wpabuf_head(req), wpabuf_len(req), 200) < 0)
 	{
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 
 	wpabuf_free(req);
@@ -908,7 +905,7 @@
 
 	m = p2p_group_get_client_iface(group, client_interface_addr);
 	if (m == NULL || m->client_info == NULL) {
-		wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
+		p2p_dbg(group->p2p, "Client was not in this group");
 		return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
 	}
 
@@ -921,9 +918,9 @@
 	else
 		curr_noa_len = -1;
 	if (curr_noa_len < 0)
-		wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
+		p2p_dbg(group->p2p, "Failed to fetch current NoA");
 	else if (curr_noa_len == 0)
-		wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
+		p2p_dbg(group->p2p, "No NoA being advertized");
 	else
 		wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
 			    curr_noa_len);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d5ce52f..dc629f8 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -398,6 +398,7 @@
 	} start_after_scan;
 	u8 after_scan_peer[ETH_ALEN];
 	struct p2p_pending_action_tx *after_scan_tx;
+	unsigned int after_scan_tx_in_progress:1;
 
 	/* Requested device types for find/search */
 	unsigned int num_req_dev_types;
@@ -569,9 +570,8 @@
 
 /* p2p_utils.c */
 int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-			u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
 void p2p_channels_intersect(const struct p2p_channels *a,
 			    const struct p2p_channels *b,
 			    struct p2p_channels *res);
@@ -730,5 +730,11 @@
 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);
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
 
 #endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 3beefd2..6b3dafb 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -166,8 +166,7 @@
 
 	os_memset(group_bssid, 0, sizeof(group_bssid));
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Invitation Request from " MACSTR " (freq=%d)",
+	p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)",
 		MAC2STR(sa), rx_freq);
 
 	if (p2p_parse(data, len, &msg))
@@ -175,14 +174,12 @@
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invitation Request from unknown peer "
-			MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR,
+			MAC2STR(sa));
 
 		if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
 				   0)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Invitation Request add device failed "
+			p2p_dbg(p2p, "Invitation Request add device failed "
 				MACSTR, MAC2STR(sa));
 			status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 			goto fail;
@@ -190,18 +187,16 @@
 
 		dev = p2p_get_device(p2p, sa);
 		if (dev == NULL) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Reject Invitation Request from unknown "
-				"peer " MACSTR, MAC2STR(sa));
+			p2p_dbg(p2p, "Reject Invitation Request from unknown peer "
+				MACSTR, MAC2STR(sa));
 			status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 			goto fail;
 		}
 	}
 
 	if (!msg.group_id || !msg.channel_list) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory attribute missing in Invitation "
-			"Request from " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from "
+			MACSTR, MAC2STR(sa));
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 	}
@@ -214,46 +209,42 @@
 		 * the request was for a persistent group if the attribute is
 		 * missing.
 		 */
-		wpa_printf(MSG_DEBUG, "P2P: Mandatory Invitation Flags "
-			   "attribute missing from Invitation Request");
+		p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request");
 		persistent = 1;
 	}
 
 	if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
 				    msg.channel_list, msg.channel_list_len) <
 	    0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No common channels found");
+		p2p_dbg(p2p, "No common channels found");
 		status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 		goto fail;
 	}
 
+	p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+			       &intersection);
+
 	if (p2p->cfg->invitation_process) {
 		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);
+			&go, group_bssid, &op_freq, persistent, &intersection);
 	}
 
 	if (op_freq) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
-			"processing forced frequency %d MHz", op_freq);
-		if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
-					&reg_class, &channel) < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unknown forced freq %d MHz from "
-				"invitation_process()", op_freq);
+		p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
+			op_freq);
+		if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
+			p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()",
+				op_freq);
 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 			goto fail;
 		}
 
-		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-				       &intersection);
 		if (!p2p_channels_includes(&intersection, reg_class, channel))
 		{
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: forced freq %d MHz not in the supported "
-				"channels interaction", op_freq);
+			p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+				op_freq);
 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 			goto fail;
 		}
@@ -261,28 +252,21 @@
 		if (status == P2P_SC_SUCCESS)
 			channels = &intersection;
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No forced channel from invitation processing - "
-			"figure out best one to use");
+		p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
 
-		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-				       &intersection);
 		/* Default to own configuration as a starting point */
 		p2p->op_reg_class = p2p->cfg->op_reg_class;
 		p2p->op_channel = p2p->cfg->op_channel;
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own default "
-			"op_class %d channel %d",
+		p2p_dbg(p2p, "Own default op_class %d channel %d",
 			p2p->op_reg_class, p2p->op_channel);
 
 		/* Use peer preference if specified and compatible */
 		if (msg.operating_channel) {
 			int req_freq;
 			req_freq = p2p_channel_to_freq(
-				(const char *) msg.operating_channel,
 				msg.operating_channel[3],
 				msg.operating_channel[4]);
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
-				"operating channel preference: %d MHz",
+			p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
 				req_freq);
 			if (req_freq > 0 &&
 			    p2p_channels_includes(&intersection,
@@ -290,56 +274,45 @@
 						  msg.operating_channel[4])) {
 				p2p->op_reg_class = msg.operating_channel[3];
 				p2p->op_channel = msg.operating_channel[4];
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: Use peer preference op_class %d "
-					"channel %d",
+				p2p_dbg(p2p, "Use peer preference op_class %d channel %d",
 					p2p->op_reg_class, p2p->op_channel);
 			} else {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: Cannot use peer channel "
-					"preference");
+				p2p_dbg(p2p, "Cannot use peer channel preference");
 			}
 		}
 
 		if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
 					   p2p->op_channel)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Initially selected channel (op_class %d "
-				"channel %d) not in channel intersection - try "
-				"to reselect",
+			p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
 				p2p->op_reg_class, p2p->op_channel);
 			p2p_reselect_channel(p2p, &intersection);
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Re-selection result: op_class %d "
-				"channel %d",
+			p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
 				p2p->op_reg_class, p2p->op_channel);
 			if (!p2p_channels_includes(&intersection,
 						   p2p->op_reg_class,
 						   p2p->op_channel)) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: Peer does not support selected "
-					"operating channel (reg_class=%u "
-					"channel=%u)",
+				p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)",
 					p2p->op_reg_class, p2p->op_channel);
 				status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 				goto fail;
 			}
+		} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+			   !p2p->cfg->cfg_op_channel) {
+			p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
+				p2p->op_reg_class, p2p->op_channel);
+			p2p_reselect_channel(p2p, &intersection);
 		}
 
-		op_freq = p2p_channel_to_freq(p2p->cfg->country,
-					      p2p->op_reg_class,
+		op_freq = p2p_channel_to_freq(p2p->op_reg_class,
 					      p2p->op_channel);
 		if (op_freq < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unknown operational channel "
-				"(country=%c%c reg_class=%u channel=%u)",
+			p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)",
 				p2p->cfg->country[0], p2p->cfg->country[1],
 				p2p->op_reg_class, p2p->op_channel);
 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
 			goto fail;
 		}
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
-			"channel - %d MHz", op_freq);
+		p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq);
 
 		if (status == P2P_SC_SUCCESS) {
 			reg_class = p2p->op_reg_class;
@@ -362,12 +335,10 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown regulatory class/channel");
+		p2p_dbg(p2p, "Unknown regulatory class/channel");
 		goto out;
 	}
 
@@ -394,8 +365,7 @@
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 
 out:
@@ -411,21 +381,18 @@
 	struct p2p_message msg;
 	struct p2p_channels intersection, *channels = NULL;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Invitation Response from " MACSTR,
+	p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
 		MAC2STR(sa));
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Invitation Response from unknown peer "
+		p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
 			MACSTR, MAC2STR(sa));
 		return;
 	}
 
 	if (dev != p2p->invite_peer) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore unexpected Invitation Response from peer "
+		p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
 			MACSTR, MAC2STR(sa));
 		return;
 	}
@@ -434,17 +401,15 @@
 		return;
 
 	if (!msg.status) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Status attribute missing in "
-			"Invitation Response from " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
+			MACSTR, MAC2STR(sa));
 		p2p_parse_free(&msg);
 		return;
 	}
 
 	if (!msg.channel_list) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Mandatory Channel List attribute missing in "
-			"Invitation Response from " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
+			MACSTR, MAC2STR(sa));
 #ifdef CONFIG_P2P_STRICT
 		p2p_parse_free(&msg);
 		return;
@@ -454,8 +419,7 @@
 	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
 					   msg.channel_list,
 					   msg.channel_list_len) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No common channels found");
+		p2p_dbg(p2p, "No common channels found");
 		p2p_parse_free(&msg);
 		return;
 	} else {
@@ -484,9 +448,8 @@
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
 	if (freq <= 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Listen/Operating frequency known for the "
-			"peer " MACSTR " to send Invitation Request",
+		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+			MACSTR " to send Invitation Request",
 			MAC2STR(dev->info.p2p_device_addr));
 		return -1;
 	}
@@ -496,8 +459,7 @@
 		return -1;
 	if (p2p->state != P2P_IDLE)
 		p2p_stop_listen_for_freq(p2p, freq);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending Invitation Request");
+	p2p_dbg(p2p, "Sending Invitation Request");
 	p2p_set_state(p2p, P2P_INVITE);
 	p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
 	p2p->invite_peer = dev;
@@ -505,8 +467,7 @@
 	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) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		/* Use P2P find to recover and retry */
 		p2p_set_timeout(p2p, 0, 0);
 	}
@@ -519,12 +480,10 @@
 
 void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Invitation Request TX callback: success=%d", success);
+	p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success);
 
 	if (p2p->invite_peer == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No pending Invite");
+		p2p_dbg(p2p, "No pending Invite");
 		return;
 	}
 
@@ -533,25 +492,17 @@
 	 * channel.
 	 */
 	p2p_set_state(p2p, P2P_INVITE);
-#ifdef ANDROID_P2P
-	p2p_set_timeout(p2p, 0, 350000);
-#else
-	p2p_set_timeout(p2p, 0, 100000);
-#endif
+	p2p_set_timeout(p2p, 0, success ? 350000 : 100000);
 }
 
 
 void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
 {
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Invitation Response TX callback: success=%d", success);
+	p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
 	if (!success)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Assume Invitation Response was actually "
-			"received by the peer even though Ack was not "
-			"reported");
+		p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported");
 
 	if (p2p->cfg->invitation_received) {
 		p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
@@ -572,28 +523,24 @@
 {
 	struct p2p_device *dev;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Request to invite peer " MACSTR " role=%d persistent=%d "
+	p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
 		"force_freq=%u",
 		MAC2STR(peer), role, persistent_group, force_freq);
 	if (bssid)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invitation for BSSID " MACSTR, MAC2STR(bssid));
+		p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
 	if (go_dev_addr) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invitation for GO Device Address " MACSTR,
+		p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR,
 			MAC2STR(go_dev_addr));
 		os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN);
 		p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf;
 	} else
 		p2p->invite_go_dev_addr = NULL;
-	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Invitation for SSID",
+	wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
 			  ssid, ssid_len);
 
 	dev = p2p_get_device(p2p, peer);
 	if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Cannot invite unknown P2P Device " MACSTR,
+		p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
 			MAC2STR(peer));
 		return -1;
 	}
@@ -610,8 +557,7 @@
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
 		if (!(dev->info.dev_capab &
 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Cannot invite a P2P Device " MACSTR
+			p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR
 				" that is in a group and is not discoverable",
 				MAC2STR(peer));
 		}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index a1268e4..54aa428 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -141,22 +141,19 @@
 	if (p2p_parse(data, len, &msg))
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Provision Discovery Request from " MACSTR
+	p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
 		" with config methods 0x%x (freq=%d)",
 		MAC2STR(sa), msg.wps_config_methods, rx_freq);
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Provision Discovery Request from "
-			"unknown peer " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
+			MACSTR, MAC2STR(sa));
 
 		if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
 				   0)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			        "P2P: Provision Discovery Request add device "
-				"failed " MACSTR, MAC2STR(sa));
+			p2p_dbg(p2p, "Provision Discovery Request add device failed "
+				MACSTR, MAC2STR(sa));
 		}
 	} else if (msg.wfd_subelems) {
 		wpabuf_free(dev->info.wfd_subelems);
@@ -166,8 +163,7 @@
 	if (!(msg.wps_config_methods &
 	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
 	       WPS_CONFIG_PUSHBUTTON))) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
-			"Config Methods in Provision Discovery Request");
+		p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
 		goto out;
 	}
 
@@ -180,8 +176,7 @@
 				break;
 		}
 		if (i == p2p->num_groups) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
-				"request for unknown P2P Group ID - reject");
+			p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
 			goto out;
 		}
 	}
@@ -190,12 +185,12 @@
 		dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
 				P2P_DEV_PD_PEER_KEYPAD);
 	if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+		p2p_dbg(p2p, "Peer " MACSTR
 			" requested us to show a PIN on display", MAC2STR(sa));
 		if (dev)
 			dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+		p2p_dbg(p2p, "Peer " MACSTR
 			" requested us to write its PIN using keypad",
 			MAC2STR(sa));
 		if (dev)
@@ -212,17 +207,14 @@
 		p2p_parse_free(&msg);
 		return;
 	}
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Sending Provision Discovery Response");
+	p2p_dbg(p2p, "Sending Provision Discovery Response");
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unknown regulatory class/channel");
+		p2p_dbg(p2p, "Unknown regulatory class/channel");
 		wpabuf_free(resp);
 		p2p_parse_free(&msg);
 		return;
@@ -231,8 +223,7 @@
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 	}
 
 	wpabuf_free(resp);
@@ -265,24 +256,20 @@
 	if (p2p_parse(data, len, &msg))
 		return;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Provision Discovery Response from " MACSTR
+	p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
 		" with config methods 0x%x",
 		MAC2STR(sa), msg.wps_config_methods);
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || !dev->req_config_methods) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provision Discovery Response from "
-			MACSTR " with no pending request", MAC2STR(sa));
+		p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
+			" with no pending request", MAC2STR(sa));
 		p2p_parse_free(&msg);
 		return;
 	}
 
 	if (dev->dialog_token != msg.dialog_token) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provision Discovery Response with "
-			"unexpected Dialog Token %u (expected %u)",
+		p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
 			msg.dialog_token, dev->dialog_token);
 		p2p_parse_free(&msg);
 		return;
@@ -308,9 +295,7 @@
 		p2p_reset_pending_pd(p2p);
 
 	if (msg.wps_config_methods != req_config_methods) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
-			"our Provision Discovery Request (received "
-			"config_methods 0x%x expected 0x%x",
+		p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
 			msg.wps_config_methods, req_config_methods);
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
@@ -323,11 +308,11 @@
 	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
 			P2P_DEV_PD_PEER_KEYPAD);
 	if (req_config_methods & WPS_CONFIG_DISPLAY) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+		p2p_dbg(p2p, "Peer " MACSTR
 			" accepted to show a PIN on display", MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+		p2p_dbg(p2p, "Peer " MACSTR
 			" accepted to write our PIN using keypad",
 			MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
@@ -343,10 +328,8 @@
 	dev->req_config_methods = 0;
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Start GO Neg after the PD-before-GO-Neg "
-			"workaround with " MACSTR,
-			MAC2STR(dev->info.p2p_device_addr));
+		p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
+			MACSTR, MAC2STR(dev->info.p2p_device_addr));
 		dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
 		p2p_connect_send(p2p, dev);
 		return;
@@ -374,9 +357,8 @@
 		freq = dev->listen_freq > 0 ? dev->listen_freq :
 			dev->oper_freq;
 	if (freq <= 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Listen/Operating frequency known for the "
-			"peer " MACSTR " to send Provision Discovery Request",
+		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+			MACSTR " to send Provision Discovery Request",
 			MAC2STR(dev->info.p2p_device_addr));
 		return -1;
 	}
@@ -384,8 +366,7 @@
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
 		if (!(dev->info.dev_capab &
 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Cannot use PD with P2P Device " MACSTR
+			p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
 				" that is in a group and is not discoverable",
 				MAC2STR(dev->info.p2p_device_addr));
 			return -1;
@@ -405,8 +386,7 @@
 	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) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		wpabuf_free(req);
 		return -1;
 	}
@@ -428,14 +408,13 @@
 	if (dev == NULL)
 		dev = p2p_get_device_interface(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
-			"Discovery Request destination " MACSTR
+		p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
 			" not yet known", MAC2STR(peer_addr));
 		return -1;
 	}
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
-		"Request with " MACSTR " (config methods 0x%x)",
+	p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
+		" (config methods 0x%x)",
 		MAC2STR(peer_addr), config_methods);
 	if (config_methods == 0)
 		return -1;
@@ -451,9 +430,8 @@
 
 	if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
 	    p2p->state != P2P_LISTEN_ONLY) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
-			"operations; postpone Provision Discovery Request "
-			"with " MACSTR " (config methods 0x%x)",
+		p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
+			MACSTR " (config methods 0x%x)",
 			MAC2STR(peer_addr), config_methods);
 		return 0;
 	}
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index bf75605..5d9c1bb 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -157,8 +157,7 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
 			    wpabuf_head(req), wpabuf_len(req), 200) < 0)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 
 	wpabuf_free(req);
 }
@@ -235,9 +234,8 @@
 
 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
 	if (freq <= 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: No Listen/Operating frequency known for the "
-			"peer " MACSTR " to send SD Request",
+		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+			MACSTR " to send SD Request",
 			MAC2STR(dev->info.p2p_device_addr));
 		return -1;
 	}
@@ -246,8 +244,7 @@
 	if (query == NULL)
 		return -1;
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Start Service Discovery with " MACSTR,
+	p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
 		MAC2STR(dev->info.p2p_device_addr));
 
 	req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
@@ -261,8 +258,7 @@
 	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), 5000) < 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 		ret = -1;
 	}
 
@@ -290,8 +286,7 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0)
 		return;
@@ -300,14 +295,12 @@
 		return;
 
 	dialog_token = *pos++;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: GAS Initial Request from " MACSTR " (dialog token %u, "
-		"freq %d)",
+	p2p_dbg(p2p, "GAS Initial Request from " MACSTR
+		" (dialog token %u, freq %d)",
 		MAC2STR(sa), dialog_token, rx_freq);
 
 	if (*pos != WLAN_EID_ADV_PROTO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected IE in GAS Initial Request: %u", *pos);
+		p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
 		return;
 	}
 	pos++;
@@ -315,15 +308,13 @@
 	slen = *pos++;
 	next = pos + slen;
 	if (next > end || slen < 2) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid IE in GAS Initial Request");
+		p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
 		return;
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported GAS advertisement protocol id %u",
+		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
 			*pos);
 		return;
 	}
@@ -342,8 +333,7 @@
 	if (pos + 4 > end)
 		return;
 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -351,21 +341,18 @@
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid ANQP Query Request length");
+		p2p_dbg(p2p, "Invalid ANQP Query Request length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP vendor type %u", *pos);
+		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -373,8 +360,7 @@
 	if (pos + 2 > end)
 		return;
 	update_indic = WPA_GET_LE16(pos);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Service Update Indicator: %u", update_indic);
+	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
 	pos += 2;
 
 	p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
@@ -390,8 +376,7 @@
 
 	/* TODO: fix the length limit to match with the maximum frame length */
 	if (wpabuf_len(resp_tlvs) > 1400) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response long "
-			"enough to require fragmentation");
+		p2p_dbg(p2p, "SD response long enough to require fragmentation");
 		if (p2p->sd_resp) {
 			/*
 			 * TODO: Could consider storing the fragmented response
@@ -400,14 +385,12 @@
 			 * Though, that would eat more memory, so there are
 			 * also benefits to just using a single buffer.
 			 */
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
-				"previous SD response");
+			p2p_dbg(p2p, "Drop previous SD response");
 			wpabuf_free(p2p->sd_resp);
 		}
 		p2p->sd_resp = wpabuf_dup(resp_tlvs);
 		if (p2p->sd_resp == NULL) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Failed to "
-				"allocate SD response fragmentation area");
+			p2p_err(p2p, "Failed to allocate SD response fragmentation area");
 			return;
 		}
 		os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
@@ -417,8 +400,7 @@
 		resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
 					     1, p2p->srv_update_indic, NULL);
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response fits "
-			"in initial response");
+		p2p_dbg(p2p, "SD response fits in initial response");
 		resp = p2p_build_sd_response(dialog_token,
 					     WLAN_STATUS_SUCCESS, 0,
 					     p2p->srv_update_indic, resp_tlvs);
@@ -430,8 +412,7 @@
 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 
 	wpabuf_free(resp);
 }
@@ -451,8 +432,7 @@
 
 #ifdef ANDROID_P2P
 	if (p2p->state != P2P_SD_DURING_FIND) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: #### Not ignoring unexpected GAS Initial Response from "
+		p2p_dbg(p2p, "P2P: #### Not ignoring unexpected GAS Initial Response from "
 			MACSTR " state %d", MAC2STR(sa), p2p->state);
 	}
 	if (p2p->sd_peer == NULL ||
@@ -460,21 +440,18 @@
 	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
 #endif
 	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore unexpected GAS Initial Response from "
+		p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
 			MACSTR, MAC2STR(sa));
 		return;
 	}
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	p2p_clear_timeout(p2p);
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GAS Initial Response from " MACSTR " (len=%d)",
+	p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
 		MAC2STR(sa), (int) len);
 
 	if (len < 5 + 2) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Too short GAS Initial Response frame");
+		p2p_dbg(p2p, "Too short GAS Initial Response frame");
 		return;
 	}
 
@@ -484,20 +461,16 @@
 	pos += 2;
 	comeback_delay = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: dialog_token=%u status_code=%u comeback_delay=%u",
+	p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
 		dialog_token, status_code, comeback_delay);
 	if (status_code) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Service Discovery failed: status code %u",
+		p2p_dbg(p2p, "Service Discovery failed: status code %u",
 			status_code);
 		return;
 	}
 
 	if (*pos != WLAN_EID_ADV_PROTO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected IE in GAS Initial Response: %u",
-			*pos);
+		p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
 		return;
 	}
 	pos++;
@@ -505,15 +478,13 @@
 	slen = *pos++;
 	next = pos + slen;
 	if (next > end || slen < 2) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid IE in GAS Initial Response");
+		p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
 		return;
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported GAS advertisement protocol id %u",
+		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
 			*pos);
 		return;
 	}
@@ -521,27 +492,22 @@
 	pos = next;
 	/* Query Response */
 	if (pos + 2 > end) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
-			"Response");
+		p2p_dbg(p2p, "Too short Query Response");
 		return;
 	}
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
-		slen);
+	p2p_dbg(p2p, "Query Response Length: %d", slen);
 	if (pos + slen > end) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
-			"Response data");
+		p2p_dbg(p2p, "Not enough Query Response data");
 		return;
 	}
 	end = pos + slen;
 
 	if (comeback_delay) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented "
-			"response - request fragments");
+		p2p_dbg(p2p, "Fragmented response - request fragments");
 		if (p2p->sd_rx_resp) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
-				"old SD reassembly buffer");
+			p2p_dbg(p2p, "Drop old SD reassembly buffer");
 			wpabuf_free(p2p->sd_rx_resp);
 			p2p->sd_rx_resp = NULL;
 		}
@@ -553,8 +519,7 @@
 	if (pos + 4 > end)
 		return;
 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -562,21 +527,18 @@
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid ANQP Query Response length");
+		p2p_dbg(p2p, "Invalid ANQP Query Response length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP vendor type %u", *pos);
+		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -584,8 +546,7 @@
 	if (pos + 2 > end)
 		return;
 	update_indic = WPA_GET_LE16(pos);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Service Update Indicator: %u", update_indic);
+	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
 	pos += 2;
 
 	p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
@@ -595,8 +556,7 @@
 	if (p2p->sd_query) {
 		if (!p2p->sd_query->for_all_peers) {
 			struct p2p_sd_query *q;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Remove completed SD query %p",
+			p2p_dbg(p2p, "Remove completed SD query %p",
 				p2p->sd_query);
 			q = p2p->sd_query;
 			p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -624,22 +584,20 @@
 	if (len < 1)
 		return;
 	dialog_token = *data;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dialog Token: %u",
-		dialog_token);
+	p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
 	if (dialog_token != p2p->sd_resp_dialog_token) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-			"response fragment for dialog token %u", dialog_token);
+		p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
+			dialog_token);
 		return;
 	}
 
 	if (p2p->sd_resp == NULL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-			"response fragment available");
+		p2p_dbg(p2p, "No pending SD response fragment available");
 		return;
 	}
 	if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
-			"response fragment for " MACSTR, MAC2STR(sa));
+		p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
+			MAC2STR(sa));
 		return;
 	}
 
@@ -656,19 +614,16 @@
 					   wpabuf_len(p2p->sd_resp));
 	if (resp == NULL)
 		return;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send GAS Comeback "
-		"Response (frag_id %d more=%d frag_len=%d)",
+	p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
 		p2p->sd_frag_id, more, (int) frag_len);
 	p2p->sd_frag_id++;
 	p2p->sd_resp_pos += frag_len;
 
 	if (more) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: %d more bytes "
-			"remain to be sent",
+		p2p_dbg(p2p, "%d more bytes remain to be sent",
 			(int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
 	} else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: All fragments of "
-			"SD response sent");
+		p2p_dbg(p2p, "All fragments of SD response sent");
 		wpabuf_free(p2p->sd_resp);
 		p2p->sd_resp = NULL;
 	}
@@ -677,8 +632,7 @@
 	if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
 			    p2p->cfg->dev_addr,
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Failed to send Action frame");
+		p2p_dbg(p2p, "Failed to send Action frame");
 
 	wpabuf_free(resp);
 }
@@ -701,8 +655,7 @@
 
 #ifdef ANDROID_P2P
 	if (p2p->state != P2P_SD_DURING_FIND) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: #### Not ignoring unexpected GAS Comeback Response from "
+		p2p_dbg(p2p, "P2P: #### Not ignoring unexpected GAS Comeback Response from "
 			MACSTR " state %d", MAC2STR(sa), p2p->state);
 	}
 	if (p2p->sd_peer == NULL ||
@@ -710,21 +663,18 @@
 	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
 #endif
 	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore unexpected GAS Comeback Response from "
+		p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
 			MACSTR, MAC2STR(sa));
 		return;
 	}
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	p2p_clear_timeout(p2p);
 
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received GAS Comeback Response from " MACSTR " (len=%d)",
+	p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
 		MAC2STR(sa), (int) len);
 
 	if (len < 6 + 2) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Too short GAS Comeback Response frame");
+		p2p_dbg(p2p, "Too short GAS Comeback Response frame");
 		return;
 	}
 
@@ -737,22 +687,19 @@
 	pos++;
 	comeback_delay = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
+	p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
 		"comeback_delay=%u",
 		dialog_token, status_code, frag_id, more_frags,
 		comeback_delay);
 	/* TODO: check frag_id match */
 	if (status_code) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Service Discovery failed: status code %u",
+		p2p_dbg(p2p, "Service Discovery failed: status code %u",
 			status_code);
 		return;
 	}
 
 	if (*pos != WLAN_EID_ADV_PROTO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unexpected IE in GAS Comeback Response: %u",
+		p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
 			*pos);
 		return;
 	}
@@ -761,15 +708,13 @@
 	slen = *pos++;
 	next = pos + slen;
 	if (next > end || slen < 2) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid IE in GAS Comeback Response");
+		p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
 		return;
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported GAS advertisement protocol id %u",
+		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
 			*pos);
 		return;
 	}
@@ -777,22 +722,18 @@
 	pos = next;
 	/* Query Response */
 	if (pos + 2 > end) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
-			"Response");
+		p2p_dbg(p2p, "Too short Query Response");
 		return;
 	}
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
-		slen);
+	p2p_dbg(p2p, "Query Response Length: %d", slen);
 	if (pos + slen > end) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
-			"Response data");
+		p2p_dbg(p2p, "Not enough Query Response data");
 		return;
 	}
 	if (slen == 0) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response "
-			"data");
+		p2p_dbg(p2p, "No Query Response data");
 		return;
 	}
 	end = pos + slen;
@@ -809,34 +750,29 @@
 	if (pos + 4 > end)
 		return;
 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
 
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
-		"length: %u", slen);
+	p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
 	if (slen < 3 + 1) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid ANQP Query Response length");
+		p2p_dbg(p2p, "Invalid ANQP Query Response length");
 		return;
 	}
 	if (pos + 4 > end)
 		return;
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+		p2p_dbg(p2p, "Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported ANQP vendor type %u", *pos);
+		p2p_dbg(p2p, "Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -844,27 +780,23 @@
 	if (pos + 2 > end)
 		return;
 	p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic);
+	p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
 	pos += 2;
 
 skip_nqp_header:
 	if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
 		return;
 	wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly "
-		"buffer length: %u",
+	p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
 		(unsigned int) wpabuf_len(p2p->sd_rx_resp));
 
 	if (more_frags) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments "
-			"remains");
+		p2p_dbg(p2p, "More fragments remains");
 		/* TODO: what would be a good size limit? */
 		if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
 			wpabuf_free(p2p->sd_rx_resp);
 			p2p->sd_rx_resp = NULL;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long "
-				"SD response - drop it");
+			p2p_dbg(p2p, "Too long SD response - drop it");
 			return;
 		}
 		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
@@ -878,8 +810,7 @@
 	if (p2p->sd_query) {
 		if (!p2p->sd_query->for_all_peers) {
 			struct p2p_sd_query *q;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Remove completed SD query %p",
+			p2p_dbg(p2p, "Remove completed SD query %p",
 				p2p->sd_query);
 			q = p2p->sd_query;
 			p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -935,7 +866,7 @@
 
 	q->next = p2p->sd_queries;
 	p2p->sd_queries = q;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
+	p2p_dbg(p2p, "Added SD Query %p", q);
 
 	if (dst == NULL) {
 		struct p2p_device *dev;
@@ -993,8 +924,7 @@
 int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
 {
 	if (p2p_unlink_sd_query(p2p, req)) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Cancel pending SD query %p", req);
+		p2p_dbg(p2p, "Cancel pending SD query %p", req);
 #ifdef ANDROID_P2P
 		p2p->sd_dev_list = NULL;
 #endif
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 37b9361..0da2682 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -46,11 +46,17 @@
 }
 
 
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
+/**
+ * p2p_channel_to_freq - Convert channel info to frequency
+ * @op_class: Operating class
+ * @channel: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int p2p_channel_to_freq(int op_class, int channel)
 {
-	/* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
-	/* TODO: more regulatory classes */
-	switch (reg_class) {
+	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+	/* TODO: more operating classes */
+	switch (op_class) {
 	case 81:
 		/* channels 1..13 */
 		if (channel < 1 || channel > 13)
@@ -94,75 +100,34 @@
 
 
 /**
- * p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
- * @channel: Channel number
- * Returns: Frequency in MHz or -1 if the specified channel is unknown
- */
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
-{
-	if (country[2] == 0x04)
-		return p2p_channel_to_freq_j4(reg_class, channel);
-
-	/* These are mainly for backwards compatibility; to be removed */
-	switch (reg_class) {
-	case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
-		if (channel < 36 || channel > 48)
-			return -1;
-		return 5000 + 5 * channel;
-	case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
-	case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
-		if (channel < 149 || channel > 161)
-			return -1;
-		return 5000 + 5 * channel;
-	case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
-	case 12: /* US/12 = 2.407 GHz, channels 1..11 */
-	case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
-		if (channel < 1 || channel > 13)
-			return -1;
-		return 2407 + 5 * channel;
-	case 31: /* JP/31 = 2.414 GHz, channel 14 */
-		if (channel != 14)
-			return -1;
-		return 2414 + 5 * channel;
-	}
-
-	return -1;
-}
-
-
-/**
  * p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
  * @channel: Buffer for returning channel number
  * Returns: 0 on success, -1 if the specified frequency is unknown
  */
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-			u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
 {
 	/* TODO: more operating classes */
 	if (freq >= 2412 && freq <= 2472) {
-		*reg_class = 81; /* 2.407 GHz, channels 1..13 */
+		*op_class = 81; /* 2.407 GHz, channels 1..13 */
 		*channel = (freq - 2407) / 5;
 		return 0;
 	}
 
 	if (freq == 2484) {
-		*reg_class = 82; /* channel 14 */
+		*op_class = 82; /* channel 14 */
 		*channel = 14;
 		return 0;
 	}
 
 	if (freq >= 5180 && freq <= 5240) {
-		*reg_class = 115; /* 5 GHz, channels 36..48 */
+		*op_class = 115; /* 5 GHz, channels 36..48 */
 		*channel = (freq - 5000) / 5;
 		return 0;
 	}
 
 	if (freq >= 5745 && freq <= 5805) {
-		*reg_class = 124; /* 5 GHz, channels 149..161 */
+		*op_class = 124; /* 5 GHz, channels 149..161 */
 		*channel = (freq - 5000) / 5;
 		return 0;
 	}
@@ -261,9 +226,8 @@
 	for (i = 0; i < channels->reg_classes; i++) {
 		const struct p2p_reg_class *reg = &channels->reg_class[i];
 		for (j = 0; j < reg->channels; j++) {
-			if (p2p_channel_to_freq_j4(reg->reg_class,
-						   reg->channel[j]) ==
-			    (int) freq)
+			if (p2p_channel_to_freq(reg->reg_class,
+						reg->channel[j]) == (int) freq)
 				return 1;
 		}
 	}
@@ -274,9 +238,36 @@
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
 	u8 op_reg_class, op_channel;
-	if (p2p_freq_to_channel(p2p->cfg->country, freq,
-				&op_reg_class, &op_channel) < 0)
+	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);
 }
+
+
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+			       const struct p2p_channels *channels)
+{
+	unsigned int i;
+	int freq = 0;
+
+	if (channels == NULL) {
+		if (p2p->cfg->num_pref_chan) {
+			freq = p2p_channel_to_freq(
+				p2p->cfg->pref_chan[0].op_class,
+				p2p->cfg->pref_chan[0].chan);
+			if (freq < 0)
+				freq = 0;
+		}
+		return freq;
+	}
+
+	for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+		freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
+					   p2p->cfg->pref_chan[i].chan);
+		if (p2p_channels_includes_freq(channels, freq))
+			return freq;
+	}
+
+	return 0;
+}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 5b2d711..0144c9f 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -223,6 +223,11 @@
 	u16 pwd_group;
 
 	/**
+	 * server_id - Server identity
+	 */
+	const char *server_id;
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
@@ -511,6 +516,8 @@
 	eap_conf.tnc = data->tnc;
 	eap_conf.wps = data->wps;
 	eap_conf.pwd_group = data->pwd_group;
+	eap_conf.server_id = (const u8 *) data->server_id;
+	eap_conf.server_id_len = os_strlen(data->server_id);
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
 	if (sess->eap == NULL) {
@@ -1280,6 +1287,7 @@
 	data->tnc = conf->tnc;
 	data->wps = conf->wps;
 	data->pwd_group = conf->pwd_group;
+	data->server_id = conf->server_id;
 	if (conf->eap_req_id_text) {
 		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
 		if (data->eap_req_id_text) {
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 82466c3..284bd59 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -144,6 +144,11 @@
 	u16 pwd_group;
 
 	/**
+	 * server_id - Server identity
+	 */
+	const char *server_id;
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index df67583..33fa1a2 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -15,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 static const int pmksa_cache_max_entries = 32;
 
@@ -164,17 +164,23 @@
 				pmksa->pmksa = pos->next;
 			else
 				prev->next = pos->next;
-			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
-				   "the current AP");
-			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 
 			/*
 			 * If OKC is used, there may be other PMKSA cache
 			 * entries based on the same PMK. These needs to be
 			 * flushed so that a new entry can be created based on
-			 * the new PMK.
+			 * the new PMK. Only clear other entries if they have a
+			 * matching PMK and this PMK has been used successfully
+			 * with the current AP, i.e., if opportunistic flag has
+			 * been cleared in wpa_supplicant_key_neg_complete().
 			 */
-			pmksa_cache_flush(pmksa, network_ctx);
+			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+				   "the current AP and any PMKSA cache entry "
+				   "that was based on the old PMK");
+			if (!pos->opportunistic)
+				pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+						  pos->pmk_len);
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 			break;
 		}
 		prev = pos;
@@ -235,15 +241,22 @@
  * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
  */
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+		       const u8 *pmk, size_t pmk_len)
 {
 	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
 	int removed = 0;
 
 	entry = pmksa->pmksa;
 	while (entry) {
-		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+		if ((entry->network_ctx == network_ctx ||
+		     network_ctx == NULL) &&
+		    (pmk == NULL ||
+		     (pmk_len == entry->pmk_len &&
+		      os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
 			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
 				   "for " MACSTR, MAC2STR(entry->aa));
 			if (prev)
@@ -509,4 +522,4 @@
 	return pmksa;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 6f3dfb3..6cbf89a 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -44,7 +44,7 @@
 	PMKSA_EXPIRE,
 };
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -66,9 +66,10 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
 			      void *network_ctx, const u8 *aa);
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+		       const u8 *pmk, size_t pmk_len);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -121,10 +122,11 @@
 }
 
 static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
-				     void *network_ctx)
+				     void *network_ctx,
+				     const u8 *pmk, size_t pmk_len)
 {
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index ab61867..c51620e 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -18,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -508,4 +508,4 @@
 	return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/src/rsn_supp/preauth.h b/src/rsn_supp/preauth.h
index 27d3112..277f066 100644
--- a/src/rsn_supp/preauth.h
+++ b/src/rsn_supp/preauth.h
@@ -11,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@
 			   int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -74,6 +74,6 @@
 	return 0;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PREAUTH_H */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8ceaf6c..539aa25 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -37,8 +37,10 @@
 #endif /* CONFIG_TDLS_TESTING */
 
 #define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
 
 #define TDLS_MIC_LEN		16
 
@@ -86,6 +88,7 @@
 
 struct wpa_tdls_peer {
 	struct wpa_tdls_peer *next;
+	unsigned int reconfig_key:1;
 	int initiator; /* whether this end was initiator for TDLS setup */
 	u8 addr[ETH_ALEN]; /* other end MAC address */
 	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
@@ -126,6 +129,8 @@
 
 	u8 qos_info;
 
+	u16 aid;
+
 	u8 *ext_capab;
 	size_t ext_capab_len;
 };
@@ -241,8 +246,13 @@
 
 	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 
-	peer->sm_tmr.count = TPK_RETRY_COUNT;
-	peer->sm_tmr.timer = TPK_TIMEOUT;
+	if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+		peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+		peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+	} else {
+		peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+		peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+	}
 
 	/* Copy message to resend on timeout */
 	os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
@@ -258,7 +268,8 @@
 
 	wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
 		   "(action_code=%u)", action_code);
-	eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+	eloop_register_timeout(peer->sm_tmr.timer / 1000,
+			       (peer->sm_tmr.timer % 1000) * 1000,
 			       wpa_tdls_tpk_retry_timeout, sm, peer);
 	return 0;
 }
@@ -293,7 +304,6 @@
 
 	if (peer->sm_tmr.count) {
 		peer->sm_tmr.count--;
-		peer->sm_tmr.timer = TPK_TIMEOUT;
 
 		wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
 			   "(action_code=%u)",
@@ -320,7 +330,8 @@
 		}
 
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
-		eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+		eloop_register_timeout(peer->sm_tmr.timer / 1000,
+				       (peer->sm_tmr.timer % 1000) * 1000,
 				       wpa_tdls_tpk_retry_timeout, sm, peer);
 	} else {
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
@@ -616,6 +627,7 @@
 		   MAC2STR(peer->addr));
 	eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
 	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+	peer->reconfig_key = 0;
 	peer->initiator = 0;
 	os_free(peer->sm_tmr.buf);
 	peer->sm_tmr.buf = NULL;
@@ -694,13 +706,8 @@
 		return -1;
 	pos = rbuf;
 
-	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) {
-		if (reason_code != WLAN_REASON_DEAUTH_LEAVING) {
-			/* Overwrite the reason code */
-			reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
-		}
+	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
 		goto skip_ies;
-	}
 
 	ftie = (struct wpa_tdls_ftie *) pos;
 	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
@@ -1340,7 +1347,8 @@
 	peer->supp_rates_len = merge_byte_arrays(
 		peer->supp_rates, sizeof(peer->supp_rates),
 		kde->supp_rates + 2, kde->supp_rates_len - 2,
-		kde->ext_supp_rates + 2, kde->ext_supp_rates_len - 2);
+		kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+		kde->ext_supp_rates_len - 2);
 	return 0;
 }
 
@@ -1556,6 +1564,8 @@
 
 	peer->qos_info = kde.qosinfo;
 
+	peer->aid = kde.aid;
+
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
 		peer = wpa_tdls_add_peer(sm, src_addr, NULL);
@@ -1733,7 +1743,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, NULL, 0, NULL, NULL, 0,
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
 				NULL, 0);
 
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
@@ -1751,7 +1761,7 @@
 }
 
 
-static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	peer->tpk_success = 1;
 	eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
@@ -1775,13 +1785,23 @@
 	}
 
 	/* add supported rates, capabilities, and qos_info to the TDLS peer */
-	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
-				peer->supp_rates, peer->supp_rates_len,
-				peer->ht_capabilities, peer->vht_capabilities,
-				peer->qos_info, peer->ext_capab,
-				peer->ext_capab_len);
+	if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
+				    peer->capability,
+				    peer->supp_rates, peer->supp_rates_len,
+				    peer->ht_capabilities,
+				    peer->vht_capabilities,
+				    peer->qos_info, peer->ext_capab,
+				    peer->ext_capab_len) < 0)
+		return -1;
 
-	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+	if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
+			   "driver");
+		return -1;
+	}
+	peer->reconfig_key = 0;
+
+	return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
 
 
@@ -1800,6 +1820,7 @@
 	int ielen;
 	u16 status;
 	const u8 *pos;
+	int ret;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1896,6 +1917,8 @@
 
 	peer->qos_info = kde.qosinfo;
 
+	peer->aid = kde.aid;
+
 	if (!wpa_tdls_get_privacy(sm)) {
 		peer->rsnie_p_len = 0;
 		peer->cipher = WPA_CIPHER_NONE;
@@ -1992,7 +2015,15 @@
 		return -1;
 	}
 
-	wpa_tdls_set_key(sm, peer);
+	if (wpa_tdls_set_key(sm, peer) < 0) {
+		/*
+		 * Some drivers may not be able to config the key prior to full
+		 * STA entry having been configured.
+		 */
+		wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+			   "STA entry is complete");
+		peer->reconfig_key = 1;
+	}
 
 skip_rsn:
 	peer->dtoken = dtoken;
@@ -2001,9 +2032,13 @@
 		   "TPK Handshake Message 3");
 	wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
 
-	wpa_tdls_enable_link(sm, peer);
-
-	return 0;
+	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, 1);
+	}
+	return ret;
 
 error:
 	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
@@ -2026,6 +2061,7 @@
 	u16 status;
 	const u8 *pos;
 	u32 lifetime;
+	int ret;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
 		   "(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -2136,13 +2172,24 @@
 		return -1;
 	}
 
-	if (wpa_tdls_set_key(sm, peer) < 0)
-		return -1;
+	if (wpa_tdls_set_key(sm, peer) < 0) {
+		/*
+		 * Some drivers may not be able to config the key prior to full
+		 * STA entry having been configured.
+		 */
+		wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+			   "STA entry is complete");
+		peer->reconfig_key = 1;
+	}
 
 skip_rsn:
-	wpa_tdls_enable_link(sm, peer);
-
-	return 0;
+	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, 1);
+	}
+	return ret;
 }
 
 
@@ -2199,7 +2246,7 @@
 	peer->initiator = 1;
 
 	/* add the peer to the driver as a "setup in progress" peer */
-	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, NULL, 0,
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
 				NULL, 0);
 
 	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e50404c..292255c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -392,7 +392,6 @@
 
 	os_memset(&ie, 0, sizeof(ie));
 
-#ifndef CONFIG_NO_WPA2
 	if (sm->proto == WPA_PROTO_RSN) {
 		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
 		const u8 *_buf = (const u8 *) (key + 1);
@@ -405,7 +404,6 @@
 				    "Authenticator", ie.pmkid, PMKID_LEN);
 		}
 	}
-#endif /* CONFIG_NO_WPA2 */
 
 	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
 	if (res == -2) {
@@ -664,7 +662,6 @@
 				       const u8 *gtk, size_t gtk_len,
 				       int key_info)
 {
-#ifndef CONFIG_NO_WPA2
 	struct wpa_gtk_data gd;
 
 	/*
@@ -703,9 +700,6 @@
 	wpa_supplicant_key_neg_complete(sm, sm->bssid,
 					key_info & WPA_KEY_INFO_SECURE);
 	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2412,6 +2406,21 @@
 }
 
 
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+	struct wpa_ie_data rsn;
+
+	if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+		return 0;
+
+	if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+	    rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+		return 1;
+
+	return 0;
+}
+
+
 /**
  * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2586,11 +2595,7 @@
 
 int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 {
-#ifndef CONFIG_NO_WPA2
 	return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2621,9 +2626,7 @@
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
 {
-#ifndef CONFIG_NO_WPA2
-	pmksa_cache_flush(sm->pmksa, network_ctx);
-#endif /* CONFIG_NO_WPA2 */
+	pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
 }
 
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index dbb493e..26e9c6c 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -56,7 +56,7 @@
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
-	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
 				u16 capability, const u8 *supp_rates,
 				size_t supp_rates_len,
 				const struct ieee80211_ht_capabilities *ht_capab,
@@ -123,6 +123,7 @@
 
 int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
 		      int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
 
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
 
@@ -244,6 +245,11 @@
 	return 0;
 }
 
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+	return 0;
+}
+
 static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
 				      int pairwise)
 {
@@ -315,6 +321,7 @@
 			    int ft_action, const u8 *target_ap,
 			    const u8 *ric_ies, size_t ric_ies_len);
 int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 				 size_t ies_len, const u8 *src_addr);
 int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
@@ -346,6 +353,10 @@
 	return 0;
 }
 
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
 static inline int
 wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 			     const u8 *src_addr)
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 4b08a62..3a40c96 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -534,6 +534,13 @@
 }
 
 
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+	if (sm != NULL)
+		sm->ft_completed = 0;
+}
+
+
 static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
 				      size_t gtk_elem_len)
 {
@@ -589,6 +596,13 @@
 	}
 
 	wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+	if (sm->group_cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		u8 tmp[8];
+		os_memcpy(tmp, gtk + 16, 8);
+		os_memcpy(gtk + 16, gtk + 24, 8);
+		os_memcpy(gtk + 24, tmp, 8);
+	}
 	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
 			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 877e6de..0e0d373 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -282,7 +282,7 @@
 
 static inline int
 wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
-			u16 capability, const u8 *supp_rates,
+			u16 aid, u16 capability, const u8 *supp_rates,
 			size_t supp_rates_len,
 			const struct ieee80211_ht_capabilities *ht_capab,
 			const struct ieee80211_vht_capabilities *vht_capab,
@@ -290,7 +290,7 @@
 {
 	if (sm->ctx->tdls_peer_addset)
 		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
-						 capability, supp_rates,
+						 aid, capability, supp_rates,
 						 supp_rates_len, ht_capab,
 						 vht_capab, qosinfo,
 						 ext_capab, ext_capab_len);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 652197f..50b9272 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -107,7 +107,6 @@
 			      int key_mgmt, int mgmt_group_cipher,
 			      struct wpa_sm *sm)
 {
-#ifndef CONFIG_NO_WPA2
 	u8 *pos;
 	struct rsn_ie_hdr *hdr;
 	u16 capab;
@@ -220,9 +219,6 @@
 	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
 
 	return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -430,6 +426,9 @@
 		} else if (*pos == WLAN_EID_HT_CAP) {
 			ie->ht_capabilities = pos + 2;
 			ie->ht_capabilities_len = pos[1];
+		} else if (*pos == WLAN_EID_VHT_AID) {
+			if (pos[1] >= 2)
+				ie->aid = WPA_GET_LE16(pos + 2);
 		} else if (*pos == WLAN_EID_VHT_CAP) {
 			ie->vht_capabilities = pos + 2;
 			ie->vht_capabilities_len = pos[1];
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 82a5c08..2c78801 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -54,6 +54,7 @@
 	const u8 *vht_capabilities;
 	size_t vht_capabilities_len;
 	u8 qosinfo;
+	u16 aid;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 87c5178..06540bf 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -443,17 +443,16 @@
 			return -1;
 		}
 
-		val = os_malloc(hdr.length + 1);
+		val = dup_binstr(hdr.payload, hdr.length);
 		if (val == NULL) {
 			x509_free_name(name);
 			return -1;
 		}
-		os_memcpy(val, hdr.payload, hdr.length);
-		val[hdr.length] = '\0';
 		if (os_strlen(val) != hdr.length) {
 			wpa_printf(MSG_INFO, "X509: Reject certificate with "
 				   "embedded NUL byte in a string (%s[NUL])",
 				   val);
+			os_free(val);
 			x509_free_name(name);
 			return -1;
 		}
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 0f1f191..940b4d8 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -14,6 +14,7 @@
 
 LIB_OBJS= \
 	base64.o \
+	bitfield.o \
 	common.o \
 	ip_addr.o \
 	radiotap.o \
diff --git a/src/utils/bitfield.c b/src/utils/bitfield.c
new file mode 100644
index 0000000..f90e4be
--- /dev/null
+++ b/src/utils/bitfield.c
@@ -0,0 +1,89 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, 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 "bitfield.h"
+
+
+struct bitfield {
+	u8 *bits;
+	size_t max_bits;
+};
+
+
+struct bitfield * bitfield_alloc(size_t max_bits)
+{
+	struct bitfield *bf;
+
+	bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
+	if (bf == NULL)
+		return NULL;
+	bf->bits = (u8 *) (bf + 1);
+	bf->max_bits = max_bits;
+	return bf;
+}
+
+
+void bitfield_free(struct bitfield *bf)
+{
+	os_free(bf);
+}
+
+
+void bitfield_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] |= BIT(bit % 8);
+}
+
+
+void bitfield_clear(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] &= ~BIT(bit % 8);
+}
+
+
+int bitfield_is_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return 0;
+	return !!(bf->bits[bit / 8] & BIT(bit % 8));
+}
+
+
+static int first_zero(u8 val)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (!(val & 0x01))
+			return i;
+		val >>= 1;
+	}
+	return -1;
+}
+
+
+int bitfield_get_first_zero(struct bitfield *bf)
+{
+	size_t i;
+	for (i = 0; i <= (bf->max_bits + 7) / 8; i++) {
+		if (bf->bits[i] != 0xff)
+			break;
+	}
+	if (i > (bf->max_bits + 7) / 8)
+		return -1;
+	i = i * 8 + first_zero(bf->bits[i]);
+	if (i >= bf->max_bits)
+		return -1;
+	return i;
+}
diff --git a/src/utils/bitfield.h b/src/utils/bitfield.h
new file mode 100644
index 0000000..7050a20
--- /dev/null
+++ b/src/utils/bitfield.h
@@ -0,0 +1,21 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BITFIELD_H
+#define BITFIELD_H
+
+struct bitfield;
+
+struct bitfield * bitfield_alloc(size_t max_bits);
+void bitfield_free(struct bitfield *bf);
+void bitfield_set(struct bitfield *bf, size_t bit);
+void bitfield_clear(struct bitfield *bf, size_t bit);
+int bitfield_is_set(struct bitfield *bf, size_t bit);
+int bitfield_get_first_zero(struct bitfield *bf);
+
+#endif /* BITFIELD_H */
diff --git a/src/utils/build_config.h b/src/utils/build_config.h
index f947388..c6f4e43 100644
--- a/src/utils/build_config.h
+++ b/src/utils/build_config.h
@@ -47,31 +47,4 @@
 #endif /* USE_INTERNAL_CRYPTO */
 #endif /* CONFIG_WIN32_DEFAULTS */
 
-#ifdef CONFIG_XCODE_DEFAULTS
-#define CONFIG_DRIVER_OSX
-#define CONFIG_BACKEND_FILE
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_UNIX
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define CONFIG_WPS
-#define EAP_WSC
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_XCODE_DEFAULTS */
-
 #endif /* BUILD_CONFIG_H */
diff --git a/src/utils/common.c b/src/utils/common.c
index e636984..bf326cd 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -517,11 +517,9 @@
 		if (pos == NULL || pos[1] != '\0')
 			return NULL;
 		*len = pos - value;
-		str = os_malloc(*len + 1);
+		str = dup_binstr(value, *len);
 		if (str == NULL)
 			return NULL;
-		os_memcpy(str, value, *len);
-		str[*len] = '\0';
 		return str;
 	} else if (*value == 'P' && value[1] == '"') {
 		const char *pos;
@@ -532,11 +530,9 @@
 		if (pos == NULL || pos[1] != '\0')
 			return NULL;
 		tlen = pos - value;
-		tstr = os_malloc(tlen + 1);
+		tstr = dup_binstr(value, tlen);
 		if (tstr == NULL)
 			return NULL;
-		os_memcpy(tstr, value, tlen);
-		tstr[tlen] = '\0';
 
 		str = os_malloc(tlen + 1);
 		if (str == NULL) {
@@ -610,3 +606,19 @@
 
 	return len;
 }
+
+
+char * dup_binstr(const void *src, size_t len)
+{
+	char *res;
+
+	if (src == NULL)
+		return NULL;
+	res = os_malloc(len + 1);
+	if (res == NULL)
+		return NULL;
+	os_memcpy(res, src, len);
+	res[len] = '\0';
+
+	return res;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index a859042..e4f7031 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -487,6 +487,7 @@
 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);
+char * dup_binstr(const void *src, size_t len);
 
 static inline int is_zero_ether_addr(const u8 *a)
 {
diff --git a/src/utils/edit.c b/src/utils/edit.c
index b01e08d..177ecf4 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -345,7 +345,7 @@
 
 static void process_cmd(void)
 {
-
+	currbuf_valid = 0;
 	if (cmdbuf_len == 0) {
 		printf("\n%s> ", ps2 ? ps2 : "");
 		fflush(stdout);
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
index add26fa..c2a5bca 100644
--- a/src/utils/edit_readline.c
+++ b/src/utils/edit_readline.c
@@ -167,9 +167,9 @@
 			if (filter_cb && filter_cb(edit_cb_ctx, p)) {
 				h = remove_history(where_history());
 				if (h) {
-					os_free(h->line);
+					free(h->line);
 					free(h->data);
-					os_free(h);
+					free(h);
 				} else
 					next_history();
 			} else
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 2de3e01..f62e2b7 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -799,6 +799,7 @@
 #endif /* CONFIG_ELOOP_POLL */
 	}
 
+	eloop.terminate = 0;
 out:
 #ifndef CONFIG_ELOOP_POLL
 	os_free(rfds);
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 5511ef1..38ea8aa 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, 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.
@@ -620,7 +620,7 @@
 	va_end(ap);
 	wpa_printf(level, "%s%s", prefix, buf);
 	if (wpa_msg_cb)
-		wpa_msg_cb(ctx, level, buf, len);
+		wpa_msg_cb(ctx, level, 0, buf, len);
 	os_free(buf);
 }
 
@@ -644,9 +644,56 @@
 	va_start(ap, fmt);
 	len = vsnprintf(buf, buflen, fmt, ap);
 	va_end(ap);
-	wpa_msg_cb(ctx, level, buf, len);
+	wpa_msg_cb(ctx, level, 0, buf, len);
 	os_free(buf);
 }
+
+
+void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
+			   "message buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_printf(level, "%s", buf);
+	if (wpa_msg_cb)
+		wpa_msg_cb(ctx, level, 1, buf, len);
+	os_free(buf);
+}
+
+
+void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
+			   "message buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_printf(level, "%s", buf);
+	if (wpa_msg_cb)
+		wpa_msg_cb(ctx, level, 2, buf, len);
+	os_free(buf);
+}
+
 #endif /* CONFIG_NO_WPA_MSG */
 
 
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 339c749..2ed1bd8 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, 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.
@@ -155,6 +155,8 @@
 #ifdef CONFIG_NO_WPA_MSG
 #define wpa_msg(args...) do { } while (0)
 #define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_global(args...) do { } while (0)
+#define wpa_msg_no_global(args...) do { } while (0)
 #define wpa_msg_register_cb(f) do { } while (0)
 #define wpa_msg_register_ifname_cb(f) do { } while (0)
 #else /* CONFIG_NO_WPA_MSG */
@@ -189,8 +191,38 @@
 void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
 PRINTF_FORMAT(3, 4);
 
-typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
-				size_t len);
+/**
+ * wpa_msg_global - Global printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg(), but it sends the output as a global event,
+ * i.e., without being specific to an interface. For backwards compatibility,
+ * an old style event is also delivered on one of the interfaces (the one
+ * specified by the context data).
+ */
+void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_no_global - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg(), but it does not send the output as a global
+ * event.
+ */
+void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, int global,
+				const char *txt, size_t len);
 
 /**
  * wpa_msg_register_cb - Register callback function for wpa_msg() messages
diff --git a/src/wps/http_client.c b/src/wps/http_client.c
index c6d6c7f..0290013 100644
--- a/src/wps/http_client.c
+++ b/src/wps/http_client.c
@@ -92,7 +92,7 @@
 		   (unsigned long) wpabuf_len(c->req),
 		   (unsigned long) wpabuf_len(c->req) - c->req_pos);
 
-	res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
+	res = send(c->sd, wpabuf_head_u8(c->req) + c->req_pos,
 		   wpabuf_len(c->req) - c->req_pos, 0);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index edcc18c..ac9bb1e 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -417,3 +417,14 @@
 
 	return ie;
 }
+
+
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
+		   MAC2STR(addr));
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, addr, ETH_ALEN);
+	return 0;
+}
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 0897b7b..4e4da5e 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -343,10 +343,36 @@
 	if (wps_build_version(plain) ||
 	    wps_build_cred(&data, plain) ||
 	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
+		os_free(data.new_psk);
 		wpabuf_free(plain);
 		return NULL;
 	}
 
+	if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
+	    wps->ap) {
+		struct wps_credential cred;
+
+		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+			   "on credential token generation");
+
+		os_memset(&cred, 0, sizeof(cred));
+		os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
+		cred.ssid_len = wps->ssid_len;
+		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
+		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
+		os_memcpy(cred.key, data.new_psk, data.new_psk_len);
+		cred.key_len = data.new_psk_len;
+
+		wps->wps_state = WPS_STATE_CONFIGURED;
+		wpa_hexdump_ascii_key(MSG_DEBUG,
+				      "WPS: Generated random passphrase",
+				      data.new_psk, data.new_psk_len);
+		if (wps->cred_cb)
+			wps->cred_cb(wps->cb_ctx, &cred);
+	}
+
+	os_free(data.new_psk);
+
 	return plain;
 }
 
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 3c94a43..7a7c099 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -257,11 +257,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
 
 	os_free(dev->manufacturer);
-	dev->manufacturer = os_malloc(str_len + 1);
+	dev->manufacturer = dup_binstr(str, str_len);
 	if (dev->manufacturer == NULL)
 		return -1;
-	os_memcpy(dev->manufacturer, str, str_len);
-	dev->manufacturer[str_len] = '\0';
 
 	return 0;
 }
@@ -278,11 +276,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
 
 	os_free(dev->model_name);
-	dev->model_name = os_malloc(str_len + 1);
+	dev->model_name = dup_binstr(str, str_len);
 	if (dev->model_name == NULL)
 		return -1;
-	os_memcpy(dev->model_name, str, str_len);
-	dev->model_name[str_len] = '\0';
 
 	return 0;
 }
@@ -299,11 +295,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
 
 	os_free(dev->model_number);
-	dev->model_number = os_malloc(str_len + 1);
+	dev->model_number = dup_binstr(str, str_len);
 	if (dev->model_number == NULL)
 		return -1;
-	os_memcpy(dev->model_number, str, str_len);
-	dev->model_number[str_len] = '\0';
 
 	return 0;
 }
@@ -320,11 +314,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
 
 	os_free(dev->serial_number);
-	dev->serial_number = os_malloc(str_len + 1);
+	dev->serial_number = dup_binstr(str, str_len);
 	if (dev->serial_number == NULL)
 		return -1;
-	os_memcpy(dev->serial_number, str, str_len);
-	dev->serial_number[str_len] = '\0';
 
 	return 0;
 }
@@ -341,11 +333,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
 
 	os_free(dev->device_name);
-	dev->device_name = os_malloc(str_len + 1);
+	dev->device_name = dup_binstr(str, str_len);
 	if (dev->device_name == NULL)
 		return -1;
-	os_memcpy(dev->device_name, str, str_len);
-	dev->device_name[str_len] = '\0';
 
 	return 0;
 }
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9c0cebb..27c554f 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -16,16 +16,6 @@
 #include "wps_dev_attr.h"
 
 
-static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
-	return 0;
-}
-
-
 static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
 {
 	u8 state;
@@ -149,7 +139,7 @@
 	if (wps_build_version(msg) ||
 	    wps_build_msg_type(msg, WPS_M1) ||
 	    wps_build_uuid_e(msg, wps->uuid_e) ||
-	    wps_build_mac_addr(wps, msg) ||
+	    wps_build_mac_addr(msg, wps->mac_addr_e) ||
 	    wps_build_enrollee_nonce(wps, msg) ||
 	    wps_build_public_key(wps, msg) ||
 	    wps_build_auth_type_flags(wps, msg) ||
@@ -852,6 +842,24 @@
 		return 0;
 	}
 
+#ifdef CONFIG_P2P
+	if ((id == DEV_PW_DEFAULT &&
+	     wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) ||
+	    (id == DEV_PW_REGISTRAR_SPECIFIED &&
+	     wps->dev_pw_id == DEV_PW_DEFAULT)) {
+		/*
+		 * Common P2P use cases indicate whether the PIN is from the
+		 * client or GO using Device Password Id in M1/M2 in a way that
+		 * does not look fully compliant with WSC specification. Anyway,
+		 * this is deployed and needs to be allowed, so ignore changes
+		 * between Registrar-Specified and Default PIN.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID "
+			   "change");
+		return 0;
+	}
+#endif /* CONFIG_P2P */
+
 	wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
 		   "ID from %u to %u", wps->dev_pw_id, id);
 
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 14c1b77..5694997 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -796,52 +796,31 @@
 
 	if (attr->manufacturer) {
 		os_free(sta->manufacturer);
-		sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
-		if (sta->manufacturer) {
-			os_memcpy(sta->manufacturer, attr->manufacturer,
-				  attr->manufacturer_len);
-			sta->manufacturer[attr->manufacturer_len] = '\0';
-		}
+		sta->manufacturer = dup_binstr(attr->manufacturer,
+					       attr->manufacturer_len);
 	}
 
 	if (attr->model_name) {
 		os_free(sta->model_name);
-		sta->model_name = os_malloc(attr->model_name_len + 1);
-		if (sta->model_name) {
-			os_memcpy(sta->model_name, attr->model_name,
-				  attr->model_name_len);
-			sta->model_name[attr->model_name_len] = '\0';
-		}
+		sta->model_name = dup_binstr(attr->model_name,
+					     attr->model_name_len);
 	}
 
 	if (attr->model_number) {
 		os_free(sta->model_number);
-		sta->model_number = os_malloc(attr->model_number_len + 1);
-		if (sta->model_number) {
-			os_memcpy(sta->model_number, attr->model_number,
-				  attr->model_number_len);
-			sta->model_number[attr->model_number_len] = '\0';
-		}
+		sta->model_number = dup_binstr(attr->model_number,
+					       attr->model_number_len);
 	}
 
 	if (attr->serial_number) {
 		os_free(sta->serial_number);
-		sta->serial_number = os_malloc(attr->serial_number_len + 1);
-		if (sta->serial_number) {
-			os_memcpy(sta->serial_number, attr->serial_number,
-				  attr->serial_number_len);
-			sta->serial_number[attr->serial_number_len] = '\0';
-		}
+		sta->serial_number = dup_binstr(attr->serial_number,
+						attr->serial_number_len);
 	}
 
 	if (attr->dev_name) {
 		os_free(sta->dev_name);
-		sta->dev_name = os_malloc(attr->dev_name_len + 1);
-		if (sta->dev_name) {
-			os_memcpy(sta->dev_name, attr->dev_name,
-				  attr->dev_name_len);
-			sta->dev_name[attr->dev_name_len] = '\0';
-		}
+		sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
 	}
 
 	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
@@ -1292,6 +1271,22 @@
 	/* Limit event_id to < 32 bits to avoid issues with atoi() */
 	er->event_id &= 0x0fffffff;
 
+	if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
+		const char *pos, *end;
+		pos = filter + 7;
+		end = os_strchr(pos, ' ');
+		if (end) {
+			size_t len = end - pos;
+			os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
+				   len + 1 : sizeof(er->ifname));
+			filter = end + 1;
+		} else {
+			os_strlcpy(er->ifname, pos, sizeof(er->ifname));
+			filter = NULL;
+		}
+		er->forced_ifname = 1;
+	}
+
 	if (filter) {
 		if (inet_aton(filter, &er->filter_addr) == 0) {
 			wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
@@ -1302,10 +1297,10 @@
 		wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
 			   "with %s", filter);
 	}
-	if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
+	if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
 			   er->mac_addr)) {
 		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
-			   "for %s. Does it have IP address?", ifname);
+			   "for %s. Does it have IP address?", er->ifname);
 		wps_er_deinit(er, NULL, NULL);
 		return NULL;
 	}
diff --git a/src/wps/wps_er.h b/src/wps/wps_er.h
index 6119647..4b48ff6 100644
--- a/src/wps/wps_er.h
+++ b/src/wps/wps_er.h
@@ -76,6 +76,7 @@
 struct wps_er {
 	struct wps_context *wps;
 	char ifname[17];
+	int forced_ifname;
 	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
 	char *ip_addr_text; /* IP address of network i.f. we use */
 	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
diff --git a/src/wps/wps_er_ssdp.c b/src/wps/wps_er_ssdp.c
index f9f6e6c..e381fec 100644
--- a/src/wps/wps_er_ssdp.c
+++ b/src/wps/wps_er_ssdp.c
@@ -166,7 +166,9 @@
 		return -1;
 	}
 
-	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr,
+						    er->forced_ifname ?
+						    er->ifname : NULL);
 	if (er->multicast_sd < 0) {
 		wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
 			   "for SSDP");
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 6efc3bf..413379b 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -169,6 +169,7 @@
 			 const struct wpabuf *pubkey, const u8 *dev_pw,
 			 size_t dev_pw_len);
 struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr);
 
 /* wps_attr_process.c */
 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
@@ -196,7 +197,8 @@
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
 int wps_device_store(struct wps_registrar *reg,
 		     struct wps_device_data *dev, const u8 *uuid);
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+					      u16 dev_pw_id);
 const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
 int wps_registrar_pbc_overlap(struct wps_registrar *reg,
 			      const u8 *addr, const u8 *uuid_e);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 86ef022..d182f14 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -771,7 +771,7 @@
 	else
 		wps_registrar_add_authorized_mac(
 			reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
 			       wps_registrar_set_selected_timeout,
@@ -793,7 +793,7 @@
 		addr = pin->enrollee_addr;
 	wps_registrar_remove_authorized_mac(reg, addr);
 	wps_remove_pin(pin);
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -956,7 +956,7 @@
 	os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
 	wps_registrar_remove_authorized_mac(reg,
 					    (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -1004,7 +1004,7 @@
 		os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
 	wps_registrar_add_authorized_mac(reg,
 					 (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
@@ -1027,7 +1027,7 @@
 	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	reg->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -1531,18 +1531,6 @@
 }
 
 
-static int wps_build_cred_mac_addr(struct wpabuf *msg,
-				   const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
-		   MAC2STR(cred->mac_addr));
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
-	return 0;
-}
-
-
 static int wps_build_credential(struct wpabuf *msg,
 				const struct wps_credential *cred)
 {
@@ -1551,7 +1539,7 @@
 	    wps_build_cred_auth_type(msg, cred) ||
 	    wps_build_cred_encr_type(msg, cred) ||
 	    wps_build_cred_network_key(msg, cred) ||
-	    wps_build_cred_mac_addr(msg, cred))
+	    wps_build_mac_addr(msg, cred->mac_addr))
 		return -1;
 	return 0;
 }
@@ -3296,7 +3284,7 @@
 		   "unselect internal Registrar");
 	reg->selected_registrar = 0;
 	reg->pbc = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -3368,7 +3356,8 @@
  * This function is called when selected registrar state changes, e.g., when an
  * AP receives a SetSelectedRegistrar UPnP message.
  */
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+					      u16 dev_pw_id)
 {
 	wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
 
@@ -3392,7 +3381,8 @@
 			reg->sel_reg_dev_password_id_override =
 				DEV_PW_PUSHBUTTON;
 			wps_set_pushbutton(&methods, reg->wps->config_methods);
-		}
+		} else if (dev_pw_id)
+			reg->sel_reg_dev_password_id_override = dev_pw_id;
 		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
 			   "(pbc=%d)", reg->pbc);
 		reg->sel_reg_config_methods_override = methods;
@@ -3514,12 +3504,15 @@
 	reg->pbc = 0;
 	wps_registrar_add_authorized_mac(reg,
 					 (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, pw_id);
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
 			       wps_registrar_set_selected_timeout,
 			       reg, NULL);
 
+	wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar",
+		   pw_id);
+
 	return 0;
 }
 
@@ -3561,7 +3554,7 @@
 {
 	wps_registrar_remove_authorized_mac(reg,
 					    (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 09a46a2..bea2b33 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -322,11 +322,9 @@
 	url_len -= 7;
 
 	/* Make a copy of the string to allow modification during parsing */
-	scratch_mem = os_malloc(url_len + 1);
+	scratch_mem = dup_binstr(url, url_len);
 	if (scratch_mem == NULL)
 		goto fail;
-	os_memcpy(scratch_mem, url, url_len);
-	scratch_mem[url_len] = '\0';
 	wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
 	host = scratch_mem;
 	path = os_strchr(host, '/');
@@ -984,6 +982,7 @@
 
 	wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
 	web_listener_stop(sm);
+	ssdp_listener_stop(sm);
 	upnp_wps_free_msearchreply(&sm->msearch_replies);
 	upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
 
@@ -997,7 +996,6 @@
 	if (sm->multicast_sd >= 0)
 		close(sm->multicast_sd);
 	sm->multicast_sd = -1;
-	ssdp_listener_stop(sm);
 
 	sm->started = 0;
 }
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index 54ed98f..4f1dd8f 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -22,7 +22,7 @@
 	struct wps_registrar *reg = timeout_ctx;
 	wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
 	s->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -71,7 +71,7 @@
 				       upnp_er_set_selected_timeout, s, reg);
 	}
 
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 
 	return 0;
 }
@@ -83,5 +83,5 @@
 	s->selected_registrar = 0;
 	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
 	if (reg)
-		wps_registrar_selected_registrar_changed(reg);
+		wps_registrar_selected_registrar_changed(reg, 0);
 }
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index 7f3c561..5c39f7e 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -171,7 +171,7 @@
 int ssdp_listener_start(struct upnp_wps_device_sm *sm);
 int ssdp_listener_open(void);
 int add_ssdp_network(const char *net_if);
-int ssdp_open_multicast_sock(u32 ip_addr);
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname);
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
 
 /* wps_upnp_web.c */
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 17a8207..416961c 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2000-2003 Intel Corporation
  * Copyright (c) 2006-2007 Sony Corporation
  * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * See wps_upnp.c for more details on licensing and code history.
  */
@@ -13,6 +13,9 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <net/route.h>
+#ifdef __linux__
+#include <net/if.h>
+#endif /* __linux__ */
 
 #include "common.h"
 #include "uuid.h"
@@ -854,7 +857,7 @@
 }
 
 
-int ssdp_open_multicast_sock(u32 ip_addr)
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname)
 {
 	int sd;
 	 /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
@@ -865,6 +868,22 @@
 	if (sd < 0)
 		return -1;
 
+	if (forced_ifname) {
+#ifdef __linux__
+		struct ifreq req;
+		os_memset(&req, 0, sizeof(req));
+		os_strlcpy(req.ifr_name, forced_ifname, sizeof(req.ifr_name));
+		if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &req,
+			       sizeof(req)) < 0) {
+			wpa_printf(MSG_INFO, "WPS UPnP: Failed to bind "
+				   "multicast socket to ifname %s: %s",
+				   forced_ifname, strerror(errno));
+			close(sd);
+			return -1;
+		}
+#endif /* __linux__ */
+	}
+
 #if 0   /* maybe ok if we sometimes block on writes */
 	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
 		close(sd);
@@ -924,7 +943,7 @@
  */
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
 {
-	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr, NULL);
 	if (sm->multicast_sd < 0)
 		return -1;
 	return 0;
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index ce0bede..11386d8 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -996,13 +996,11 @@
 				h++;
 			len = end - h;
 			os_free(callback_urls);
-			callback_urls = os_malloc(len + 1);
+			callback_urls = dup_binstr(h, len);
 			if (callback_urls == NULL) {
 				ret = HTTP_INTERNAL_SERVER_ERROR;
 				goto error;
 			}
-			os_memcpy(callback_urls, h, len);
-			callback_urls[len] = 0;
 			continue;
 		}
 		/* SID is only for renewal */
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index a0c97f0..8515b5a 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -236,7 +236,7 @@
 NEED_MD5=y
 NEED_RC4=y
 else
-L_CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+L_CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -286,10 +286,6 @@
 NEED_GAS=y
 endif
 
-ifdef CONFIG_NO_WPA2
-L_CFLAGS += -DCONFIG_NO_WPA2
-endif
-
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
 ifdef CONFIG_AP
@@ -601,6 +597,22 @@
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+L_CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += src/eap_peer/eap_eke.so
+else
+L_CFLAGS += -DEAP_EKE
+OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c
+OBJS_h += src/eap_server/eap_server_eke.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_WPS
 ifdef CONFIG_WPS2
 L_CFLAGS += -DCONFIG_WPS2
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 0634219..5698619 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -215,7 +215,7 @@
 NEED_MD5=y
 NEED_RC4=y
 else
-CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -265,10 +265,6 @@
 NEED_GAS=y
 endif
 
-ifdef CONFIG_NO_WPA2
-CFLAGS += -DCONFIG_NO_WPA2
-endif
-
 include ../src/drivers/drivers.mak
 ifdef CONFIG_AP
 OBJS_d += $(DRV_BOTH_OBJS)
@@ -579,6 +575,22 @@
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_eke.so
+else
+CFLAGS += -DEAP_EKE
+OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o
+OBJS_h += ../src/eap_server/eap_server_eke.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_WPS
 ifdef CONFIG_WPS2
 CFLAGS += -DCONFIG_WPS2
@@ -1581,6 +1593,10 @@
 	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
 		-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
 
+eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_eke_register=eap_peer_method_dynamic_init
+
 %.so: %.c
 	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
 		-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index d84e61e..78df89e 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -115,13 +115,15 @@
 - NetBSD-current
 - Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
 - drivers:
-	Linux drivers that support WPA/WPA2 configuration with the generic
-	Linux wireless extensions (WE-18 or newer). Even though there are
+	Linux drivers that support cfg80211/nl80211. Even though there are
 	number of driver specific interface included in wpa_supplicant, please
-	note that Linux drivers are moving to use generic wireless extensions
-	and driver_wext (-Dwext on wpa_supplicant command line) should be the
-	default option to start with before falling back to driver specific
-	interface.
+	note that Linux drivers are moving to use generic wireless configuration
+	interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line)
+	should be the default option to start with before falling back to driver
+	specific interface.
+
+	Linux drivers that support WPA/WPA2 configuration with the generic
+	Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211.
 
 	In theory, any driver that supports Linux wireless extensions can be
 	used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
@@ -408,6 +410,7 @@
 
 usage:
   wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+        [-G<group>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
         [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
         [-p<driver_param>] [-b<br_ifname>] ...]
@@ -422,6 +425,7 @@
   -D = driver name (can be multiple drivers: nl80211,wext)
   -f = Log output to default log location (normally /tmp)
   -g = global ctrl_interface
+  -G = global ctrl_interface group
   -K = include keys (passwords, etc.) in debug output
   -t = include timestamp in debug messages
   -h = show this help text
@@ -436,6 +440,7 @@
   -N = start describing new interface
 
 drivers:
+  nl80211 = Linux nl80211/cfg80211
   wext = Linux wireless extensions (generic)
   wired = wpa_supplicant wired Ethernet driver
   roboswitch = wpa_supplicant Broadcom switch driver
@@ -477,7 +482,7 @@
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
 
-wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
+wpa_supplicant -cw.conf -Dnl80211 -iwlan0 -bbr0
 
 
 Configuration file
@@ -869,10 +874,10 @@
 # Start wpa_supplicant in the background
 wpa_supplicant -g/var/run/wpa_supplicant-global -B
 
-# Add a new interface (wlan0, no configuration file, driver=wext, and
+# Add a new interface (wlan0, no configuration file, driver=nl80211, and
 # enable control interface)
 wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
-	"" wext /var/run/wpa_supplicant
+	"" nl80211 /var/run/wpa_supplicant
 
 # Configure a network using the newly added network interface:
 wpa_cli -iwlan0 add_network
@@ -933,7 +938,7 @@
   chmod 0750 /var/run/wpa_priv
 - start wpa_priv as root (e.g., from system startup scripts) with the
   enabled interfaces configured on the command line:
-  wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0
+  wpa_priv -B -P /var/run/wpa_priv.pid nl80211:wlan0
 - run wpa_supplicant as non-root with a user that is in wpapriv group:
   wpa_supplicant -i ath0 -c wpa_supplicant.conf
 
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index b86c4c7..8b3d6b4 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -176,7 +176,7 @@
 CONFIG_EAP_LEAP=y
 
 # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
-#CONFIG_EAP_AKA=y
+CONFIG_EAP_AKA=y
 
 # EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
 # This requires CONFIG_EAP_AKA to be enabled, too.
@@ -201,10 +201,12 @@
 # Enable WSC 2.0 support
 CONFIG_WPS2=y
 # Enable WPS external registrar functionality
-#CONFIG_WPS_ER=y
+CONFIG_WPS_ER=y
 # Disable credentials for an open network by default when acting as a WPS
 # registrar.
 #CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+CONFIG_WPS_NFC=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -234,6 +236,7 @@
 # unix = UNIX domain sockets (default for Linux/*BSD)
 # udp = UDP sockets using localhost (127.0.0.1)
 # named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
 # y = use default (backwards compatibility)
 # If this option is commented out, control interface is not included in the
 # build.
@@ -259,11 +262,6 @@
 # 35-50 kB in code size.
 #CONFIG_NO_WPA=y
 
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
 # Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
 # This option can be used to reduce code size by removing support for
 # converting ASCII passphrases into PSK. If this functionality is removed, the
@@ -325,9 +323,7 @@
 # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
 CONFIG_PEERKEY=y
 
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
+# IEEE 802.11w (management frame protection), also known as PMF
 # Driver support is also needed for IEEE 802.11w.
 #CONFIG_IEEE80211W=y
 
@@ -486,6 +482,10 @@
 # IEEE 802.11n (High Throughput) support (mainly for AP mode)
 CONFIG_IEEE80211N=y
 
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
 # Interworking (IEEE 802.11u)
 # This can be used to enable functionality to improve interworking with
 # external networks (GAS/ANQP to learn more about the networks and network
@@ -498,12 +498,39 @@
 # Disable roaming in wpa_supplicant
 CONFIG_NO_ROAMING=y
 
-# Enable TDLS
-CONFIG_TDLS=y
-
-# Enable P2P
-CONFIG_P2P=y
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
 CONFIG_AP=y
 
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+CONFIG_P2P=y
+
+CONFIG_TDLS=y
+
 #Enable Wifi Display
 CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 3ba4496..c48a286 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -55,21 +55,14 @@
 		/* default channel 11 */
 		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
 		conf->channel = 11;
-	} else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-		conf->channel = (ssid->frequency - 2407) / 5;
-	} else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
-		   (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
-		conf->channel = (ssid->frequency - 5000) / 5;
-	} else if (ssid->frequency >= 56160 + 2160 * 1 &&
-		   ssid->frequency <= 56160 + 2160 * 4) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
-		conf->channel = (ssid->frequency - 56160) / 2160;
 	} else {
-		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
-			   ssid->frequency);
-		return -1;
+		conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+						       &conf->channel);
+		if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+			wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: "
+				   "%d MHz", ssid->frequency);
+			return -1;
+		}
 	}
 
 	/* TODO: enable HT40 if driver supports it;
@@ -131,7 +124,9 @@
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
-	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+	    (ssid->mode == WPAS_MODE_P2P_GO ||
+	     ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
 		/* Remove 802.11b rates from supported and basic rate sets */
 		int *list = os_malloc(4 * sizeof(int));
 		if (list) {
@@ -251,6 +246,16 @@
 		bss->rsn_pairwise = WPA_CIPHER_NONE;
 	}
 
+	if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+	    (bss->wpa_group == WPA_CIPHER_CCMP ||
+	     bss->wpa_group == WPA_CIPHER_GCMP)) {
+		/*
+		 * Strong ciphers do not need frequent rekeying, so increase
+		 * the default GTK rekeying period to 24 hours.
+		 */
+		bss->wpa_group_rekey = 86400;
+	}
+
 #ifdef CONFIG_WPS
 	/*
 	 * Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -489,6 +494,11 @@
 
 	if (wpa_drv_associate(wpa_s, &params) < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
+#ifdef CONFIG_P2P
+		if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION &&
+		    wpa_s->global->p2p_group_formation == wpa_s)
+			wpas_p2p_group_formation_failed(wpa_s->parent);
+#endif /* CONFIG_P2P */
 		return -1;
 	}
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0d98884..a35be51 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -322,11 +322,9 @@
 			return 0;
 		ssid->psk_set = 0;
 		os_free(ssid->passphrase);
-		ssid->passphrase = os_malloc(len + 1);
+		ssid->passphrase = dup_binstr(value, len);
 		if (ssid->passphrase == NULL)
 			return -1;
-		os_memcpy(ssid->passphrase, value, len);
-		ssid->passphrase[len] = '\0';
 		return 0;
 #else /* CONFIG_NO_PBKDF2 */
 		wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
@@ -1524,6 +1522,7 @@
 	{ INT(eap_workaround) },
 	{ STRe(pac_file) },
 	{ INTe(fragment_size) },
+	{ INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
 	{ INT_RANGE(mode, 0, 4) },
 	{ INT_RANGE(proactive_key_caching, 0, 1) },
@@ -1828,6 +1827,7 @@
 	os_free(config->pssid);
 	os_free(config->p2p_pref_chan);
 	os_free(config->autoscan);
+	os_free(config->freq_list);
 	wpabuf_free(config->wps_nfc_dh_pubkey);
 	wpabuf_free(config->wps_nfc_dh_privkey);
 	wpabuf_free(config->wps_nfc_dev_pw);
@@ -2585,6 +2585,7 @@
 	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
 	config->max_num_sta = DEFAULT_MAX_NUM_STA;
 	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+	config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
 	config->wmm_ac_params[0] = ac_be;
 	config->wmm_ac_params[1] = ac_bk;
 	config->wmm_ac_params[2] = ac_vi;
@@ -2735,6 +2736,21 @@
 }
 
 
+static int wpa_config_process_freq_list(const struct global_parse_data *data,
+					struct wpa_config *config, int line,
+					const char *value)
+{
+	int *freqs;
+
+	freqs = wpa_config_parse_int_array(value);
+	if (freqs == NULL)
+		return -1;
+	os_free(config->freq_list);
+	config->freq_list = freqs;
+	return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
 				      struct wpa_config *config, int line,
 				      const char *pos)
@@ -3090,6 +3106,9 @@
 	{ INT(beacon_int), 0 },
 	{ FUNC(ap_vendor_elements), 0 },
 	{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+	{ FUNC(freq_list), 0 },
+	{ INT(scan_cur_freq), 0 },
+	{ INT(sched_scan_interval), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 4a175ce..1748cf3 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -24,6 +24,7 @@
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
 #define DEFAULT_MAX_NUM_STA 128
 #define DEFAULT_ACCESS_NETWORK_TYPE 15
+#define DEFAULT_SCAN_CUR_FREQ 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -645,6 +646,22 @@
 	unsigned int max_num_sta;
 
 	/**
+	 * freq_list - Array of allowed scan frequencies or %NULL for all
+	 *
+	 * This is an optional zero-terminated array of frequencies in
+	 * megahertz (MHz) to allow for narrowing scanning range.
+	 */
+	int *freq_list;
+
+	/**
+	 * scan_cur_freq - Whether to scan only the current channel
+	 *
+	 * If true, attempt to scan only the current channel if any other
+	 * VIFs on this radio are already associated on a particular channel.
+	 */
+	int scan_cur_freq;
+
+	/**
 	 * changed_parameters - Bitmap of changed parameters since last update
 	 */
 	unsigned int changed_parameters;
@@ -854,6 +871,11 @@
 	 * allowing it to update the internal BSS table.
 	 */
 	int ignore_old_scan_res;
+
+	/**
+	 * sched_scan_interval -  schedule scan interval
+	 */
+	unsigned int sched_scan_interval;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8604ae8..d03de0b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1015,6 +1015,22 @@
 	if (config->ignore_old_scan_res)
 		fprintf(f, "ignore_old_scan_res=%d\n",
 			config->ignore_old_scan_res);
+
+	if (config->freq_list && config->freq_list[0]) {
+		int i;
+		fprintf(f, "freq_list=");
+		for (i = 0; config->freq_list[i]; i++) {
+			fprintf(f, "%s%u", i > 0 ? " " : "",
+				config->freq_list[i]);
+		}
+		fprintf(f, "\n");
+	}
+	if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
+		fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+
+	if (config->sched_scan_interval)
+		fprintf(f, "sched_scan_interval=%u\n",
+			config->sched_scan_interval);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ad0392f..a24abaf 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -461,6 +461,14 @@
 			return -1;
 		return res;
 #endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_TESTING_GET_GTK
+	} else if (os_strcmp(cmd, "gtk") == 0) {
+		if (wpa_s->last_gtk_len == 0)
+			return -1;
+		res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
+				       wpa_s->last_gtk_len);
+		return res;
+#endif /* CONFIG_TESTING_GET_GTK */
 	}
 
 	if (res < 0 || (unsigned int) res >= buflen)
@@ -2963,6 +2971,60 @@
 }
 
 
+static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
+					  char *buf, size_t buflen)
+{
+	struct hostapd_channel_data *chnl;
+	int ret, i, j;
+	char *pos, *end, *hmode;
+
+	pos = buf;
+	end = pos + buflen;
+
+	for (j = 0; j < wpa_s->hw.num_modes; j++) {
+		switch (wpa_s->hw.modes[j].mode) {
+		case HOSTAPD_MODE_IEEE80211B:
+			hmode = "B";
+			break;
+		case HOSTAPD_MODE_IEEE80211G:
+			hmode = "G";
+			break;
+		case HOSTAPD_MODE_IEEE80211A:
+			hmode = "A";
+			break;
+		case HOSTAPD_MODE_IEEE80211AD:
+			hmode = "AD";
+			break;
+		default:
+			continue;
+		}
+		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
+				  hmode);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		chnl = wpa_s->hw.modes[j].channels;
+		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			ret = os_snprintf(pos, end - pos, " %d = %d MHz%s\n",
+					  chnl[i].chan, chnl[i].freq,
+					  chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
+					  " (NO_IBSS)" : "");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
 static int wpa_supplicant_ctrl_iface_get_capability(
 	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
 	size_t buflen)
@@ -3020,6 +3082,9 @@
 	if (os_strcmp(field, "channels") == 0)
 		return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
 
+	if (os_strcmp(field, "freq") == 0)
+		return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
 		   field);
 
@@ -4937,26 +5002,92 @@
 	return ret;
 }
 
+
+static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int query_reason;
+
+	query_reason = atoi(cmd);
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
+		   query_reason);
+
+	return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+}
+
 #endif /* CONFIG_WNM */
 
 
+/* Get string representation of channel width */
+static const char * channel_width_name(enum chan_width width)
+{
+	switch (width) {
+	case CHAN_WIDTH_20_NOHT:
+		return "20 MHz (no HT)";
+	case CHAN_WIDTH_20:
+		return "20 MHz";
+	case CHAN_WIDTH_40:
+		return "40 MHz";
+	case CHAN_WIDTH_80:
+		return "80 MHz";
+	case CHAN_WIDTH_80P80:
+		return "80+80 MHz";
+	case CHAN_WIDTH_160:
+		return "160 MHz";
+	default:
+		return "unknown";
+	}
+}
+
+
 static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
 				      size_t buflen)
 {
 	struct wpa_signal_info si;
 	int ret;
+	char *pos, *end;
 
 	ret = wpa_drv_signal_poll(wpa_s, &si);
 	if (ret)
 		return -1;
 
-	ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+	pos = buf;
+	end = buf + buflen;
+
+	ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
 			  "NOISE=%d\nFREQUENCY=%u\n",
 			  si.current_signal, si.current_txrate / 1000,
 			  si.current_noise, si.frequency);
-	if (ret < 0 || (unsigned int) ret > buflen)
+	if (ret < 0 || ret > end - pos)
 		return -1;
-	return ret;
+	pos += ret;
+
+	if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+		ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+				  channel_width_name(si.chanwidth));
+		if (ret < 0 || ret > end - pos)
+			return -1;
+		pos += ret;
+	}
+
+	if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+		ret = os_snprintf(pos, end - pos,
+				  "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
+				  si.center_frq1, si.center_frq2);
+		if (ret < 0 || ret > end - pos)
+			return -1;
+		pos += ret;
+	}
+
+	if (si.avg_signal) {
+		ret = os_snprintf(pos, end - pos,
+				  "AVG_RSSI=%d\n", si.avg_signal);
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+
+	return pos - buf;
 }
 
 
@@ -5019,6 +5150,9 @@
 	wpa_tdls_enable(wpa_s->wpa, 1);
 #endif /* CONFIG_TDLS */
 
+	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+	wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+
 	wpa_s->no_keep_alive = 0;
 
 	os_free(wpa_s->disallow_aps_bssid);
@@ -5035,6 +5169,7 @@
 
 	wpa_bss_flush(wpa_s);
 	wpa_blacklist_clear(wpa_s);
+	wpa_s->extra_blacklist_count = 0;
 	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
 	wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
 }
@@ -5573,6 +5708,9 @@
 	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
 		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
+		if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+				reply_len = -1;
 #endif /* CONFIG_WNM */
 	} else if (os_strcmp(buf, "FLUSH") == 0) {
 		wpa_supplicant_ctrl_iface_flush(wpa_s);
@@ -5766,6 +5904,126 @@
 }
 
 
+static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
+					    const char *ifname,
+					    char *cmd, size_t *resp_len)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(ifname, wpa_s->ifname) == 0)
+			break;
+	}
+
+	if (wpa_s == NULL) {
+		char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
+		if (resp)
+			*resp_len = os_strlen(resp);
+		else
+			*resp_len = 1;
+		return resp;
+	}
+
+	return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
+}
+
+
+static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
+					       char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_P2P
+	static const char * cmd[] = {
+		"P2P_FIND",
+		"P2P_STOP_FIND",
+		"P2P_LISTEN",
+		"P2P_GROUP_ADD",
+		"P2P_GET_PASSPHRASE",
+		"P2P_SERVICE_UPDATE",
+		"P2P_SERVICE_FLUSH",
+		"P2P_FLUSH",
+		"P2P_CANCEL",
+		"P2P_PRESENCE_REQ",
+		"P2P_EXT_LISTEN",
+		NULL
+	};
+	static const char * prefix[] = {
+		"P2P_FIND ",
+		"P2P_CONNECT ",
+		"P2P_LISTEN ",
+		"P2P_GROUP_REMOVE ",
+		"P2P_GROUP_ADD ",
+		"P2P_PROV_DISC ",
+		"P2P_SERV_DISC_REQ ",
+		"P2P_SERV_DISC_CANCEL_REQ ",
+		"P2P_SERV_DISC_RESP ",
+		"P2P_SERV_DISC_EXTERNAL ",
+		"P2P_SERVICE_ADD ",
+		"P2P_SERVICE_DEL ",
+		"P2P_REJECT ",
+		"P2P_INVITE ",
+		"P2P_PEER ",
+		"P2P_SET ",
+		"P2P_UNAUTHORIZE ",
+		"P2P_PRESENCE_REQ ",
+		"P2P_EXT_LISTEN ",
+		NULL
+	};
+	int found = 0;
+	int i;
+
+	if (global->p2p_init_wpa_s == NULL)
+		return NULL;
+
+	for (i = 0; !found && cmd[i]; i++) {
+		if (os_strcmp(buf, cmd[i]) == 0)
+			found = 1;
+	}
+
+	for (i = 0; !found && prefix[i]; i++) {
+		if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
+			found = 1;
+	}
+
+	if (found)
+		return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+							 buf, resp_len);
+#endif /* CONFIG_P2P */
+	return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
+					       char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+	if (global->p2p_init_wpa_s == NULL)
+		return NULL;
+	if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
+	    os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
+		return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+							 buf, resp_len);
+#endif /* CONFIG_WIFI_DISPLAY */
+	return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
+					   char *buf, size_t *resp_len)
+{
+	char *ret;
+
+	ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
+	if (ret)
+		return ret;
+
+	ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
+	if (ret)
+		return ret;
+
+	return NULL;
+}
+
+
 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
 						char *buf, size_t *resp_len)
 {
@@ -5774,6 +6032,20 @@
 	int reply_len;
 	int level = MSG_DEBUG;
 
+	if (os_strncmp(buf, "IFNAME=", 7) == 0) {
+		char *pos = os_strchr(buf + 7, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			return wpas_global_ctrl_iface_ifname(global,
+							     buf + 7, pos,
+							     resp_len);
+		}
+	}
+
+	reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
+	if (reply)
+		return reply;
+
 	if (os_strcmp(buf, "PING") == 0)
 		level = MSG_EXCESSIVE;
 	wpa_hexdump_ascii(level, "RX global ctrl_iface",
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
index fd417ff..dc02db2 100644
--- a/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -423,7 +423,7 @@
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
 					     const char *txt, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 994f9b1..f3b660d 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -255,7 +255,7 @@
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
 					     const char *txt, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 4dfabc8..fc0d649 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-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.
@@ -50,12 +50,20 @@
 };
 
 
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+struct ctrl_iface_global_priv {
+	struct wpa_global *global;
+	int sock;
+	struct dl_list ctrl_dst;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
 					   size_t len);
 
 
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
 					    struct sockaddr_un *from,
 					    socklen_t fromlen)
 {
@@ -67,7 +75,7 @@
 	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
 	dst->addrlen = fromlen;
 	dst->debug_level = MSG_INFO;
-	dl_list_add(&priv->ctrl_dst, &dst->list);
+	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));
@@ -75,13 +83,13 @@
 }
 
 
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
 					    struct sockaddr_un *from,
 					    socklen_t fromlen)
 {
 	struct wpa_ctrl_dst *dst;
 
-	dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
+	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
 		if (fromlen == dst->addrlen &&
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
@@ -148,14 +156,16 @@
 	buf[res] = '\0';
 
 	if (os_strcmp(buf, "ATTACH") == 0) {
-		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+						     fromlen))
 			reply_len = 1;
 		else {
 			new_attached = 1;
 			reply_len = 2;
 		}
 	} else if (os_strcmp(buf, "DETACH") == 0) {
-		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+						     fromlen))
 			reply_len = 1;
 		else
 			reply_len = 2;
@@ -166,30 +176,6 @@
 		else
 			reply_len = 2;
 	} else {
-#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
-		char *ifname, *ifend;
-
-		ifname = os_strstr(buf, "interface=");
-		if (ifname != NULL) {
-			ifend = os_strchr(ifname + 10, ' ');
-			if (ifend != NULL)
-				*ifend++ = '\0';
-			else
-				*(ifname - 1) = '\0';
-			wpa_printf(MSG_DEBUG, "Found %s", ifname);
-			for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-				if (os_strcmp(wpa_s->ifname, ifname + 10) == 0)
-					break;
-			}
-			if (wpa_s == NULL) {
-				wpa_printf(MSG_ERROR, "P2P: %s does not exist", ifname);
-				wpa_s = eloop_ctx;
-			}
-			if (ifend != NULL)
-				os_memmove(ifname, ifend, strlen(ifend) + 1);
-			wpa_printf(MSG_INFO, "wpa_s->ifname %s cmd %s", wpa_s ? wpa_s->ifname : "NULL", buf);
-		}
-#endif /* defined CONFIG_P2P && defined ANDROID_P2P */
 		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
 							  &reply_len);
 	}
@@ -264,13 +250,30 @@
 }
 
 
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
 					     const char *txt, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+	if (wpa_s == NULL)
 		return;
-	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+	if (global != 2 && wpa_s->global->ctrl_iface) {
+		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+		if (!dl_list_empty(&priv->ctrl_dst)) {
+			wpa_supplicant_ctrl_iface_send(global ? NULL :
+						       wpa_s->ifname,
+						       priv->sock,
+						       &priv->ctrl_dst,
+						       level, txt, len);
+		}
+	}
+
+	if (wpa_s->ctrl_iface == NULL)
+		return;
+	wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+				       &wpa_s->ctrl_iface->ctrl_dst,
+				       level, txt, len);
 }
 
 
@@ -543,14 +546,17 @@
 
 /**
  * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @ifname: Interface name for global control socket or %NULL
+ * @sock: Local socket fd
+ * @ctrl_dst: List of attached listeners
  * @level: Priority level of the message
  * @buf: Message data
  * @len: Message length
  *
  * Send a packet to all monitor programs attached to the control interface.
  */
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+					   struct dl_list *ctrl_dst,
 					   int level, const char *buf,
 					   size_t len)
 {
@@ -558,32 +564,45 @@
 	char levelstr[10];
 	int idx, res;
 	struct msghdr msg;
-	struct iovec io[2];
+	struct iovec io[5];
 
-	if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+	if (sock < 0 || dl_list_empty(ctrl_dst))
 		return;
 
 	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
 	if (res < 0 || (size_t) res >= sizeof(levelstr))
 		return;
-	io[0].iov_base = levelstr;
-	io[0].iov_len = os_strlen(levelstr);
-	io[1].iov_base = (char *) buf;
-	io[1].iov_len = len;
+	idx = 0;
+	if (ifname) {
+		io[idx].iov_base = "IFNAME=";
+		io[idx].iov_len = 7;
+		idx++;
+		io[idx].iov_base = (char *) ifname;
+		io[idx].iov_len = os_strlen(ifname);
+		idx++;
+		io[idx].iov_base = " ";
+		io[idx].iov_len = 1;
+		idx++;
+	}
+	io[idx].iov_base = levelstr;
+	io[idx].iov_len = os_strlen(levelstr);
+	idx++;
+	io[idx].iov_base = (char *) buf;
+	io[idx].iov_len = len;
+	idx++;
 	os_memset(&msg, 0, sizeof(msg));
 	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
+	msg.msg_iovlen = idx;
 
 	idx = 0;
-	dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
-			      list) {
+	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(priv->sock, &msg, 0) < 0) {
+			if (sendmsg(sock, &msg, MSG_DONTWAIT) < 0) {
 				int _errno = errno;
 				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
 					   "%d - %s",
@@ -593,7 +612,7 @@
 				    (_errno != ENOBUFS && dst->errors > 10) ||
 				    _errno == ENOENT) {
 					wpa_supplicant_ctrl_iface_detach(
-						priv, &dst->addr,
+						ctrl_dst, &dst->addr,
 						dst->addrlen);
 				}
 			} else
@@ -626,8 +645,8 @@
 
 		if (os_strcmp(buf, "ATTACH") == 0) {
 			/* handle ATTACH signal of first monitor interface */
-			if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
-							      fromlen)) {
+			if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+							      &from, fromlen)) {
 				sendto(priv->sock, "OK\n", 3, 0,
 				       (struct sockaddr *) &from, fromlen);
 				/* OK to continue */
@@ -647,21 +666,16 @@
 
 /* Global ctrl_iface */
 
-struct ctrl_iface_global_priv {
-	struct wpa_global *global;
-	int sock;
-};
-
-
 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
 						     void *sock_ctx)
 {
 	struct wpa_global *global = eloop_ctx;
+	struct ctrl_iface_global_priv *priv = sock_ctx;
 	char buf[256];
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
-	char *reply;
+	char *reply = NULL;
 	size_t reply_len;
 
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -672,16 +686,32 @@
 	}
 	buf[res] = '\0';
 
-	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-							 &reply_len);
+	if (os_strcmp(buf, "ATTACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+						     fromlen))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+						     fromlen))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else {
+		reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+								 &reply_len);
+	}
 
 	if (reply) {
 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
 		       fromlen);
 		os_free(reply);
-	} else if (reply_len) {
+	} else if (reply_len == 1) {
 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
 		       fromlen);
+	} else if (reply_len == 2) {
+		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
 	}
 }
 
@@ -691,24 +721,48 @@
 {
 	struct ctrl_iface_global_priv *priv;
 	struct sockaddr_un addr;
+	const char *ctrl = global->params.ctrl_interface;
 
 	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)
+	if (ctrl == NULL)
 		return priv;
 
-#ifdef ANDROID
-	priv->sock = android_get_control_socket(global->params.ctrl_interface);
-	if (priv->sock >= 0)
-		goto havesock;
-#endif /* ANDROID */
+	wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
 
-	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
-		   global->params.ctrl_interface);
+#ifdef ANDROID
+	if (os_strncmp(ctrl, "@android:", 9) == 0) {
+		priv->sock = android_get_control_socket(ctrl + 9);
+		if (priv->sock < 0) {
+			wpa_printf(MSG_ERROR, "Failed to open Android control "
+				   "socket '%s'", ctrl + 9);
+			goto fail;
+		}
+		wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
+			   ctrl + 9);
+		goto havesock;
+	}
+
+	if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
+		/*
+		 * Backwards compatibility - try to open an Android control
+		 * socket and if that fails, assume this was a UNIX domain
+		 * socket instead.
+		 */
+		priv->sock = android_get_control_socket(ctrl);
+		if (priv->sock >= 0) {
+			wpa_printf(MSG_DEBUG,
+				   "Using Android control socket '%s'",
+				   ctrl);
+			goto havesock;
+		}
+	}
+#endif /* ANDROID */
 
 	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (priv->sock < 0) {
@@ -721,8 +775,23 @@
 	addr.sun_len = sizeof(addr);
 #endif /* __FreeBSD__ */
 	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, global->params.ctrl_interface,
-		   sizeof(addr.sun_path));
+
+	if (os_strncmp(ctrl, "@abstract:", 10) == 0) {
+		addr.sun_path[0] = '\0';
+		os_strlcpy(addr.sun_path + 1, ctrl + 10,
+			   sizeof(addr.sun_path) - 1);
+		if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
+		    0) {
+			wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
+				   "bind(PF_UNIX) failed: %s", strerror(errno));
+			goto fail;
+		}
+		wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
+			   ctrl + 10);
+		goto havesock;
+	}
+
+	os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 		perror("supp-global-ctrl-iface-init (will try fixup): "
 		       "bind(PF_UNIX)");
@@ -731,11 +800,11 @@
 			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
 				   " allow connections - assuming it was left"
 				   "over from forced program termination");
-			if (unlink(global->params.ctrl_interface) < 0) {
+			if (unlink(ctrl) < 0) {
 				perror("unlink[ctrl_iface]");
 				wpa_printf(MSG_ERROR, "Could not unlink "
 					   "existing ctrl_iface socket '%s'",
-					   global->params.ctrl_interface);
+					   ctrl);
 				goto fail;
 			}
 			if (bind(priv->sock, (struct sockaddr *) &addr,
@@ -745,23 +814,59 @@
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
 				   "ctrl_iface socket '%s'",
-				   global->params.ctrl_interface);
+				   ctrl);
 		} else {
 			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
 				   "be in use - cannot override it");
 			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
 				   "not used anymore",
-				   global->params.ctrl_interface);
+				   ctrl);
 			goto fail;
 		}
 	}
 
-#ifdef ANDROID
+	wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
+
+	if (global->params.ctrl_interface_group) {
+		char *gid_str = global->params.ctrl_interface_group;
+		gid_t gid = 0;
+		struct group *grp;
+		char *endp;
+
+		grp = getgrnam(gid_str);
+		if (grp) {
+			gid = grp->gr_gid;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+				   " (from group name '%s')",
+				   (int) gid, gid_str);
+		} else {
+			/* Group name not found - try to parse this as gid */
+			gid = strtol(gid_str, &endp, 10);
+			if (*gid_str == '\0' || *endp != '\0') {
+				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+					   "'%s'", gid_str);
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+				   (int) gid);
+		}
+		if (chown(ctrl, -1, gid) < 0) {
+			perror("chown[global_ctrl_interface/ifname]");
+			goto fail;
+		}
+
+		if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
+			perror("chmod[global_ctrl_interface/ifname]");
+			goto fail;
+		}
+	} else {
+		chmod(ctrl, S_IRWXU);
+	}
+
 havesock:
-#endif /* ANDROID */
 	eloop_register_read_sock(priv->sock,
 				 wpa_supplicant_global_ctrl_iface_receive,
-				 global, NULL);
+				 global, priv);
 
 	return priv;
 
@@ -776,11 +881,16 @@
 void
 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
 {
+	struct wpa_ctrl_dst *dst, *prev;
+
 	if (priv->sock >= 0) {
 		eloop_unregister_read_sock(priv->sock);
 		close(priv->sock);
 	}
 	if (priv->global->params.ctrl_interface)
 		unlink(priv->global->params.ctrl_interface);
+	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
+			      list)
+		os_free(dst);
 	os_free(priv);
 }
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5d0e31e..6caf740 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -17,6 +17,7 @@
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_old.h"
+#include "../wpa_supplicant_i.h"
 
 
 #ifndef SIGPOLL
@@ -257,6 +258,22 @@
 }
 
 
+static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+                                           DBusMessage *message, void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+
+	if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
+	                           "Disconnected")) {
+		wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
+		dbus_connection_set_exit_on_disconnect(conn, FALSE);
+		wpa_supplicant_terminate_proc(priv->global);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	} else
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
 static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
 {
 	DBusError error;
@@ -265,7 +282,10 @@
 	/* Get a reference to the system bus */
 	dbus_error_init(&error);
 	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
-	if (!priv->con) {
+	if (priv->con) {
+		dbus_connection_add_filter(priv->con, disconnect_filter, priv,
+		                           NULL);
+	} else {
 		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
 			   "bus: %s - %s", error.name, error.message);
 		ret = -1;
@@ -304,6 +324,9 @@
 						    NULL, NULL, NULL);
 		dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
 						      NULL, NULL, NULL);
+		dbus_connection_remove_filter(priv->con, disconnect_filter,
+					      priv);
+
 		dbus_connection_unref(priv->con);
 	}
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 136dd1a..ddd2c82 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -869,6 +869,76 @@
 }
 
 
+/**
+ * wpas_dbus_signal_sta - Send a station related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ * @sig_name: signal name - StaAuthorized or StaDeauthorized
+ *
+ * Notify listeners about event related with station
+ */
+static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
+				 const u8 *sta, const char *sig_name)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
+	char *dev_mac;
+
+	os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
+	dev_mac = sta_mac;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+	if (msg == NULL)
+		return;
+
+	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
+				     DBUS_TYPE_INVALID))
+		dbus_connection_send(iface->con, msg, NULL);
+	else
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+
+	wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
+		   sta_mac, sig_name);
+}
+
+
+/**
+ * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a new station has been authorized
+ */
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+				     const u8 *sta)
+{
+	wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
+}
+
+
+/**
+ * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a station has been deauthorized
+ */
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+				       const u8 *sta)
+{
+	wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
+}
+
+
 #ifdef CONFIG_P2P
 
 /**
@@ -1920,15 +1990,6 @@
 		  END_ARGS
 	  }
 	},
-#ifdef CONFIG_AUTOSCAN
-	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
-	  {
-		  { "arg", "s", ARG_IN },
-		  END_ARGS
-	  }
-	},
-#endif /* CONFIG_AUTOSCAN */
 	{ NULL, NULL, NULL, { END_ARGS } }
 };
 
@@ -2654,6 +2715,27 @@
 	  }
 	},
 #endif /* CONFIG_AP */
+	{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+	  {
+		  END_ARGS
+	  }
+	},
+#ifdef CONFIG_AUTOSCAN
+	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+	  {
+		  { "arg", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_AUTOSCAN */
 	{ NULL, NULL, NULL, { END_ARGS } }
 };
 
@@ -3005,6 +3087,18 @@
 		  END_ARGS
 	  }
 	},
+	{ "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
 	{ NULL, NULL, { END_ARGS } }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 363a7e5..61c480a 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -222,6 +222,10 @@
 			   const u8 *ie, size_t ie_len, u32 ssi_signal);
 void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
 				 const char *status, const char *parameter);
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+				     const u8 *sta);
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+				       const u8 *sta);
 
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
@@ -493,6 +497,18 @@
 {
 }
 
+static inline
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+				     const u8 *sta)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+				       const u8 *sta)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 335c25f..478d02f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1938,6 +1938,38 @@
 #endif /* CONFIG_AUTOSCAN */
 
 
+/*
+ * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogoff" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+	return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogin" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+	return NULL;
+}
+
+
 /**
  * wpas_dbus_getter_capabilities - Return interface capabilities
  * @iter: Pointer to incoming dbus message iter
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index aa56550..fbc8358 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -128,6 +128,12 @@
 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
 					  DBusError *error, void *user_data);
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index e867bae..aa6005f 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -210,6 +210,9 @@
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
 
+# EAP-EKE
+#CONFIG_EAP_EKE=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
@@ -261,11 +264,6 @@
 # 35-50 kB in code size.
 #CONFIG_NO_WPA=y
 
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
 # Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
 # This option can be used to reduce code size by removing support for
 # converting ASCII passphrases into PSK. If this functionality is removed, the
@@ -423,6 +421,10 @@
 # same file, e.g., using trace-cmd.
 #CONFIG_DEBUG_LINUX_TRACING=y
 
+# Add support for writing debug log to Android logcat instead of standard
+# output
+#CONFIG_ANDROID_LOG=y
+
 # Enable privilege separation (see README 'Privilege separation' for details)
 #CONFIG_PRIVSEP=y
 
@@ -495,6 +497,9 @@
 # Hotspot 2.0
 #CONFIG_HS20=y
 
+# Disable roaming in wpa_supplicant
+#CONFIG_NO_ROAMING=y
+
 # AP mode operations with wpa_supplicant
 # This can be used for controlling AP mode operations with wpa_supplicant. It
 # should be noted that this is mainly aimed at simple cases like
@@ -507,6 +512,9 @@
 # more information on P2P operations.
 #CONFIG_P2P=y
 
+# Enable TDLS support
+#CONFIG_TDLS=y
+
 # Autoscan
 # This can be used to enable automatic scan support in wpa_supplicant.
 # See wpa_supplicant.conf for more information on autoscan usage.
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 6bab19c..9922e07 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -129,6 +129,16 @@
 	return -1;
 }
 
+static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
+				     const u8 *addr, int reason_code)
+{
+	if (wpa_s->driver->sta_deauth) {
+		return wpa_s->driver->sta_deauth(wpa_s->drv_priv, NULL, addr,
+						 reason_code);
+	}
+	return -1;
+}
+
 static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
 					 const u8 *addr, int reason_code)
 {
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index d1eb4ff..6cd2fc5 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -135,6 +135,11 @@
 		ret = eap_peer_pwd_register();
 #endif /* EAP_PWD */
 
+#ifdef EAP_EKE
+	if (ret == 0)
+		ret = eap_peer_eke_register();
+#endif /* EAP_EKE */
+
 #ifdef EAP_SERVER_IDENTITY
 	if (ret == 0)
 		ret = eap_server_identity_register();
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 671fd74..d39216f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -44,7 +44,10 @@
 #include "interworking.h"
 
 
-static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+					      int new_scan);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
 static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
@@ -928,6 +931,15 @@
 		return -1;
 	}
 
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"Considering connect request: reassociate: %d  selected: "
+		MACSTR "  bssid: " MACSTR "  pending: " MACSTR
+		"  wpa_state: %s  ssid=%p  current_ssid=%p",
+		wpa_s->reassociate, MAC2STR(selected->bssid),
+		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+		wpa_supplicant_state_txt(wpa_s->wpa_state),
+		ssid, wpa_s->current_ssid);
+
 	/*
 	 * Do not trigger new association unless the BSSID has changed or if
 	 * reassociation is requested. If we are in process of associating with
@@ -937,22 +949,21 @@
 	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
 	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
 	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
-	      os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
-	      0))) {
+	      (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+	       os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+	       0) ||
+	      (is_zero_ether_addr(wpa_s->pending_bssid) &&
+	       ssid != wpa_s->current_ssid)))) {
 		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
 			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
 			return 0;
 		}
-		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
-			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
-			"  pending: " MACSTR "  wpa_state: %s",
-			wpa_s->reassociate, MAC2STR(selected->bssid),
-			MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
-			wpa_supplicant_state_txt(wpa_s->wpa_state));
+		wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+			MAC2STR(selected->bssid));
 		wpa_supplicant_associate(wpa_s, selected, ssid);
 	} else {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
-			"selected AP");
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+			"connect with the selected AP");
 	}
 
 	return 0;
@@ -1214,11 +1225,12 @@
 
 	wpa_scan_results_free(scan_res);
 
-	return wpas_select_network_from_last_scan(wpa_s);
+	return wpas_select_network_from_last_scan(wpa_s, 1);
 }
 
 
-static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+					      int new_scan)
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
@@ -1229,7 +1241,8 @@
 		int skip;
 		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
 		if (skip) {
-			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+			if (new_scan)
+				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 			return 0;
 		}
 
@@ -1237,7 +1250,8 @@
 			wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
 			return -1;
 		}
-		wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+		if (new_scan)
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 		/*
 		 * Do not notify other virtual radios of scan results since we do not
 		 * want them to start other associations at the same time.
@@ -1249,7 +1263,8 @@
 		if (ssid) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
 			wpa_supplicant_associate(wpa_s, NULL, ssid);
-			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+			if (new_scan)
+				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 		} else {
 			int timeout_sec = wpa_s->scan_interval;
 			int timeout_usec = 0;
@@ -1354,7 +1369,7 @@
 		return -1;
 	}
 
-	return wpas_select_network_from_last_scan(wpa_s);
+	return wpas_select_network_from_last_scan(wpa_s, 0);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
@@ -1674,7 +1689,6 @@
 {
 	u8 bssid[ETH_ALEN];
 	int ft_completed;
-	struct wpa_driver_capa capa;
 
 #ifdef CONFIG_AP
 	if (wpa_s->ap_iface) {
@@ -1780,6 +1794,16 @@
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
 	    (wpa_s->current_ssid &&
 	     wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+		if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
+		    (wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
+			/*
+			 * Set the key after having received joined-IBSS event
+			 * from the driver.
+			 */
+			wpa_supplicant_set_wpa_none_key(wpa_s,
+							wpa_s->current_ssid);
+		}
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 	} else if (!ft_completed) {
@@ -1840,8 +1864,8 @@
 
 	if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
 	     wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
-	    wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
-	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
+	    wpa_s->current_ssid &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
 		/* Set static WEP keys again */
 		wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
 	}
@@ -1935,7 +1959,9 @@
 	int authenticating;
 	u8 prev_pending_bssid[ETH_ALEN];
 	struct wpa_bss *fast_reconnect = NULL;
+#ifndef CONFIG_NO_SCAN_PROCESSING
 	struct wpa_ssid *fast_reconnect_ssid = NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 	struct wpa_ssid *last_ssid;
 
 	authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
@@ -1976,7 +2002,9 @@
 			 * time for some common cases.
 			 */
 			fast_reconnect = wpa_s->current_bss;
+#ifndef CONFIG_NO_SCAN_PROCESSING
 			fast_reconnect_ssid = wpa_s->current_ssid;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
 #ifdef ANDROID
 			wpa_supplicant_req_scan(wpa_s, 0, 500000);
@@ -2473,6 +2501,7 @@
 					    data->deauth_info.ie,
 					    data->deauth_info.ie_len);
 			}
+			wpa_reset_ft_completed(wpa_s->wpa);
 		}
 #ifdef CONFIG_AP
 		if (wpa_s->ap_iface && data && data->deauth_info.addr) {
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index dbc143a..d6dec85 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -49,17 +49,22 @@
 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 " + message.encode("hex")):
+        return False
+    return True
 
 def wpas_get_config_token(id=None):
     wpas = wpas_connect()
     if (wpas == None):
         return None
     if id:
-        return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id).rstrip().decode("hex")
-    return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
+    else:
+        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+    if "FAIL" in ret:
+        return None
+    return ret.rstrip().decode("hex")
 
 
 def wpas_get_er_config_token(uuid):
@@ -241,7 +246,8 @@
     print "Done with handover"
 
 
-def wps_tag_read(tag):
+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
@@ -250,21 +256,25 @@
             print "record type " + record.type
             if record.type == "application/vnd.wfa.wsc":
                 print "WPS tag - send to wpa_supplicant"
-                wpas_tag_read(tag.ndef.message)
+                success = wpas_tag_read(tag.ndef.message)
                 break
     else:
         print "Empty tag"
 
-    print "Remove tag"
-    while tag.is_present:
-        time.sleep(0.1)
+    if wait_remove:
+        print "Remove tag"
+        while tag.is_present:
+            time.sleep(0.1)
+
+    return success
 
 
-def wps_write_config_tag(clf, id=None):
+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):
         print "Could not get WPS config token from wpa_supplicant"
+        sys.exit(1)
         return
 
     print "Touch an NFC tag"
@@ -278,7 +288,7 @@
     print "Tag found - writing"
     tag.ndef.message = data
     print "Done - remove tag"
-    while tag.is_present:
+    while wait_remove and tag.is_present:
         time.sleep(0.1)
 
 
@@ -304,7 +314,7 @@
         time.sleep(0.1)
 
 
-def wps_write_password_tag(clf):
+def wps_write_password_tag(clf, wait_remove=True):
     print "Write WPS password token"
     data = wpas_get_password_token()
     if (data == None):
@@ -322,7 +332,7 @@
     print "Tag found - writing"
     tag.ndef.message = data
     print "Done - remove tag"
-    while tag.is_present:
+    while wait_remove and tag.is_present:
         time.sleep(0.1)
 
 
@@ -359,13 +369,22 @@
 
     try:
         arg_uuid = None
-        if len(sys.argv) > 1:
+        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)
             raise SystemExit
 
+        if len(sys.argv) > 1 and sys.argv[1] == "write-config-no-wait":
+            wps_write_config_tag(clf, wait_remove=False)
+            raise SystemExit
+
         if len(sys.argv) > 2 and sys.argv[1] == "write-config-id":
             wps_write_config_tag(clf, sys.argv[2])
             raise SystemExit
@@ -378,6 +397,10 @@
             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:
             print "Waiting for a tag or peer to be touched"
 
@@ -389,13 +412,21 @@
                     wps_handover_resp(tag, None)
                 else:
                     wps_handover_resp(tag, arg_uuid)
+                if only_one:
+                    break
                 continue
 
             if tag.ndef:
-                wps_tag_read(tag)
+                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)
 
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 27bcc7a..06a97d3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -20,7 +20,7 @@
 
 
 /** GAS query timeout in seconds */
-#define GAS_QUERY_TIMEOUT_PERIOD 5
+#define GAS_QUERY_TIMEOUT_PERIOD 2
 
 
 /**
@@ -271,6 +271,11 @@
 	if (frag_id != query->next_frag_id) {
 		wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
 			   "from " MACSTR, MAC2STR(query->addr));
+		if (frag_id + 1 == query->next_frag_id) {
+			wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
+				   "retry of previous fragment");
+			return;
+		}
 		gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
 		return;
 	}
@@ -461,16 +466,20 @@
 {
 	struct gas_query_pending *query;
 	int dialog_token;
+	static int next_start = 0;
 
 	if (wpabuf_len(req) < 3)
 		return -1;
 
 	for (dialog_token = 0; dialog_token < 256; dialog_token++) {
-		if (gas_query_dialog_token_available(gas, dst, dialog_token))
+		if (gas_query_dialog_token_available(
+			    gas, dst, (next_start + dialog_token) % 256))
 			break;
 	}
 	if (dialog_token == 256)
 		return -1; /* Too many pending queries */
+	dialog_token = (next_start + dialog_token) % 256;
+	next_start = (dialog_token + 1) % 256;
 
 	query = os_zalloc(sizeof(*query));
 	if (query == NULL)
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 1404241..4048cf7 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -33,6 +33,35 @@
 }
 
 
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		    struct wpa_bss *bss)
+{
+	if (!wpa_s->conf->hs20 || !ssid)
+		return 0;
+
+	if (ssid->parent_cred)
+		return 1;
+
+	if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE))
+		return 0;
+
+	/*
+	 * This may catch some non-Hotspot 2.0 cases, but it is safer to do that
+	 * than cause Hotspot 2.0 connections without indication element getting
+	 * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element.
+	 */
+
+	if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X))
+		return 0;
+	if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP))
+		return 0;
+	if (ssid->proto != WPA_PROTO_RSN)
+		return 0;
+
+	return 1;
+}
+
+
 struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
 				    size_t payload_len)
 {
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 6eb3926..1c8481b 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -16,5 +16,7 @@
 				    size_t payload_len);
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 				  const u8 *sa, const u8 *data, size_t slen);
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		    struct wpa_bss *bss);
 
 #endif /* HS20_SUPPLICANT_H */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 046f181..687c042 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -296,6 +296,13 @@
 }
 
 
+static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
+}
+
+
 static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
 						  void *ctx),
 			     void *cb_ctx)
@@ -386,6 +393,7 @@
 	cb.get_psk = auth_get_psk;
 	cb.set_key = auth_set_key;
 	cb.for_each_sta = auth_for_each_sta;
+	cb.disconnect = ibss_rsn_disconnect;
 
 	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
 	if (ibss_rsn->auth_group == NULL) {
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index b59dd6a..36f75a1 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -408,11 +408,9 @@
 		return NULL;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
-	r->realm = os_malloc(realm_len + 1);
+	r->realm = dup_binstr(pos, realm_len);
 	if (r->realm == NULL)
 		return NULL;
-	os_memcpy(r->realm, pos, realm_len);
-	r->realm[realm_len] = '\0';
 	pos += realm_len;
 
 	if (pos + 1 > f_end) {
@@ -601,19 +599,29 @@
 
 static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
 {
-	u8 plmn[3];
+	u8 plmn[3], plmn2[3];
 	const u8 *pos, *end;
 	u8 udhl;
 
-	/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+	/*
+	 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
+	 * operator is allowed to include only two digits of the MNC, so allow
+	 * matches based on both two and three digit MNC assumptions. Since some
+	 * SIM/USIM cards may not expose MNC length conveniently, we may be
+	 * provided the default MNC length 3 here and as such, checking with MNC
+	 * length 2 is justifiable even though 3GPP TS 24.234 does not mention
+	 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
+	 * with otherwise matching values would not be good idea in general, so
+	 * this should not result in selecting incorrect networks.
+	 */
+	/* Match with 3 digit MNC */
 	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
-	plmn[1] = imsi[2] - '0';
-	/* default to MNC length 3 if unknown */
-	if (mnc_len != 2)
-		plmn[1] |= (imsi[5] - '0') << 4;
-	else
-		plmn[1] |= 0xf0;
+	plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
 	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+	/* Match with 2 digit MNC */
+	plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+	plmn2[1] = (imsi[2] - '0') | 0xf0;
+	plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
 
 	if (anqp == NULL)
 		return 0;
@@ -633,6 +641,10 @@
 	}
 	end = pos + udhl;
 
+	wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
+		   plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
+		   imsi, mnc_len);
+
 	while (pos + 2 <= end) {
 		u8 iei, len;
 		const u8 *l_end;
@@ -645,14 +657,20 @@
 		if (iei == 0 && len > 0) {
 			/* PLMN List */
 			u8 num, i;
+			wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
+				    pos, len);
 			num = *pos++;
 			for (i = 0; i < num; i++) {
-				if (pos + 3 > end)
+				if (pos + 3 > l_end)
 					break;
-				if (os_memcmp(pos, plmn, 3) == 0)
+				if (os_memcmp(pos, plmn, 3) == 0 ||
+				    os_memcmp(pos, plmn2, 3) == 0)
 					return 1; /* Found matching PLMN */
 				pos += 3;
 			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
+				    pos, len);
 		}
 
 		pos = l_end;
@@ -1339,6 +1357,8 @@
 		char *sep;
 		const char *imsi;
 		int mnc_len;
+		char imsi_buf[16];
+		size_t msin_len;
 
 #ifdef PCSC_FUNCS
 		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
@@ -1348,6 +1368,13 @@
 			goto compare;
 		}
 #endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+		if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+			imsi = wpa_s->imsi;
+			mnc_len = wpa_s->mnc_len;
+			goto compare;
+		}
+#endif /* CONFIG_EAP_PROXY */
 
 		if (cred->imsi == NULL || !cred->imsi[0] ||
 		    cred->milenage == NULL || !cred->milenage[0])
@@ -1358,11 +1385,18 @@
 		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
 			continue;
 		mnc_len = sep - cred->imsi - 3;
-		imsi = cred->imsi;
+		os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
+		sep++;
+		msin_len = os_strlen(cred->imsi);
+		if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
+			msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
+		os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
+		imsi_buf[3 + mnc_len + msin_len] = '\0';
+		imsi = imsi_buf;
 
-#ifdef PCSC_FUNCS
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
 	compare:
-#endif /* PCSC_FUNCS */
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
 		wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
 			   MACSTR, MAC2STR(bss->bssid));
 		ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 1744620..39b837e 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,7 @@
 #include "common.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "p2p_supplicant.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -25,6 +26,7 @@
 	       "usage:\n"
 	       "  wpa_supplicant [-BddhKLqqstuvW] [-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>] "
@@ -59,6 +61,7 @@
 	printf("  -f = log output to debug file instead of stdout\n");
 #endif /* CONFIG_DEBUG_FILE */
 	printf("  -g = global ctrl_interface\n"
+	       "  -G = global ctrl_interface group\n"
 	       "  -K = include keys (passwords, etc.) in debug output\n");
 #ifdef CONFIG_DEBUG_SYSLOG
 	printf("  -s = log output to syslog instead of stdout\n");
@@ -84,7 +87,7 @@
 
 	printf("example:\n"
 	       "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
-	       wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+	       wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211");
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 }
 
@@ -157,7 +160,7 @@
 
 	for (;;) {
 		c = getopt(argc, argv,
-			   "b:Bc:C:D:de:f:g:hi:I:KLNo:O:p:P:qsTtuvW");
+			   "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -197,6 +200,9 @@
 		case 'g':
 			params.ctrl_interface = optarg;
 			break;
+		case 'G':
+			params.ctrl_interface_group = optarg;
+			break;
 		case 'h':
 			usage();
 			exitcode = 0;
@@ -284,6 +290,8 @@
 	}
 
 	for (i = 0; exitcode == 0 && i < iface_count; i++) {
+		struct wpa_supplicant *wpa_s;
+
 		if ((ifaces[i].confname == NULL &&
 		     ifaces[i].ctrl_interface == NULL) ||
 		    ifaces[i].ifname == NULL) {
@@ -294,8 +302,18 @@
 			exitcode = -1;
 			break;
 		}
-		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+		wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+		if (wpa_s == NULL) {
 			exitcode = -1;
+			break;
+		}
+#ifdef CONFIG_P2P
+		if (wpa_s->global->p2p == NULL &&
+		    (wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+		    wpas_p2p_add_p2pdev_interface(wpa_s) < 0)
+			exitcode = -1;
+#endif /* CONFIG_P2P */
 	}
 
 	if (exitcode == 0)
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 4479c09..f2cbdd7 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -551,6 +551,9 @@
 	 */
 	wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+	/* Notify listeners a new station has been authorized */
+	wpas_dbus_signal_sta_authorized(wpa_s, sta);
 }
 
 
@@ -570,6 +573,9 @@
 	 */
 	wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+	/* Notify listeners a station has been deauthorized */
+	wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
 }
 
 
@@ -631,4 +637,7 @@
 			    const char *parameter)
 {
 	wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_STATUS
+		     "status='%s' parameter='%s'",
+		     status, parameter);
 }
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 4b505b5..37f5ad3 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -65,6 +65,8 @@
 #define P2P_CONCURRENT_SEARCH_DELAY 500
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
 
+#define P2P_MGMT_DEVICE_PREFIX		"p2p-dev-"
+
 enum p2p_group_removal_reason {
 	P2P_GROUP_REMOVAL_UNKNOWN,
 	P2P_GROUP_REMOVAL_SILENT,
@@ -95,6 +97,9 @@
 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);
@@ -318,9 +323,9 @@
 		gtype = "GO";
 	if (wpa_s->cross_connect_in_use) {
 		wpa_s->cross_connect_in_use = 0;
-		wpa_msg(wpa_s->parent, MSG_INFO,
-			P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
-			wpa_s->ifname, wpa_s->cross_connect_uplink);
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+			       wpa_s->ifname, wpa_s->cross_connect_uplink);
 	}
 	switch (removal_reason) {
 	case P2P_GROUP_REMOVAL_REQUESTED:
@@ -348,11 +353,14 @@
 		break;
 	}
 	if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
-		wpa_msg(wpa_s->parent, MSG_INFO,
-			P2P_EVENT_GROUP_REMOVED "%s %s%s",
-			wpa_s->ifname, gtype, reason);
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_GROUP_REMOVED "%s %s%s",
+			       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_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,
@@ -657,14 +665,15 @@
 	wpa_s->p2p_in_provisioning = 0;
 
 	if (!success) {
-		wpa_msg(wpa_s->parent, MSG_INFO,
-			P2P_EVENT_GROUP_FORMATION_FAILURE);
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_GROUP_FORMATION_FAILURE);
 		wpas_p2p_group_delete(wpa_s,
 				      P2P_GROUP_REMOVAL_FORMATION_FAILED);
 		return;
 	}
 
-	wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS);
+	wpa_msg_global(wpa_s->parent, MSG_INFO,
+		       P2P_EVENT_GROUP_FORMATION_SUCCESS);
 
 	ssid = wpa_s->current_ssid;
 	if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -711,22 +720,23 @@
 	} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
-		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-			"%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
-			"%s",
-			wpa_s->ifname, ssid_txt, ssid->frequency, psk,
-			MAC2STR(go_dev_addr),
-			persistent ? " [PERSISTENT]" : "");
+		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			       "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+			       MACSTR "%s",
+			       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+			       MAC2STR(go_dev_addr),
+			       persistent ? " [PERSISTENT]" : "");
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 	} else {
-		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-			"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
-			"go_dev_addr=" MACSTR "%s",
-			wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0,
-			ssid && ssid->passphrase ? ssid->passphrase : "",
-			MAC2STR(go_dev_addr),
-			persistent ? " [PERSISTENT]" : "");
+		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+			       "go_dev_addr=" MACSTR "%s",
+			       wpa_s->ifname, ssid_txt,
+			       ssid ? ssid->frequency : 0,
+			       ssid && ssid->passphrase ? ssid->passphrase : "",
+			       MAC2STR(go_dev_addr),
+			       persistent ? " [PERSISTENT]" : "");
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 	}
@@ -849,26 +859,30 @@
 		if (wpa_s->global->p2p_group_formation == wpa_s)
 			wpa_s->global->p2p_group_formation = NULL;
 		if (os_strlen(params->passphrase) > 0) {
-			wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-				"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
-				"go_dev_addr=" MACSTR "%s", wpa_s->ifname,
-				wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
-				ssid->frequency, params->passphrase,
-				MAC2STR(wpa_s->global->p2p_dev_addr),
-				params->persistent_group ? " [PERSISTENT]" :
-				"");
+			wpa_msg_global(wpa_s->parent, MSG_INFO,
+				       P2P_EVENT_GROUP_STARTED
+				       "%s GO ssid=\"%s\" freq=%d "
+				       "passphrase=\"%s\" go_dev_addr=" MACSTR
+				       "%s", wpa_s->ifname,
+				       wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+				       ssid->frequency, params->passphrase,
+				       MAC2STR(wpa_s->global->p2p_dev_addr),
+				       params->persistent_group ?
+				       " [PERSISTENT]" : "");
 		} else {
 			char psk[65];
 			wpa_snprintf_hex(psk, sizeof(psk), params->psk,
 					 sizeof(params->psk));
-			wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-				"%s GO ssid=\"%s\" freq=%d psk=%s "
-				"go_dev_addr=" MACSTR "%s", wpa_s->ifname,
-				wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
-				ssid->frequency, psk,
-				MAC2STR(wpa_s->global->p2p_dev_addr),
-				params->persistent_group ? " [PERSISTENT]" :
-				"");
+			wpa_msg_global(wpa_s->parent, MSG_INFO,
+				       P2P_EVENT_GROUP_STARTED
+				       "%s GO ssid=\"%s\" freq=%d psk=%s "
+				       "go_dev_addr=" MACSTR "%s",
+				       wpa_s->ifname,
+				       wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+				       ssid->frequency, psk,
+				       MAC2STR(wpa_s->global->p2p_dev_addr),
+				       params->persistent_group ?
+				       " [PERSISTENT]" : "");
 		}
 
 		if (params->persistent_group)
@@ -942,8 +956,8 @@
 	if (os_strlen(params->passphrase) > 0) {
 		ssid->passphrase = os_strdup(params->passphrase);
 		if (ssid->passphrase == NULL) {
-			wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
-				"passphrase for GO");
+			wpa_msg_global(wpa_s, MSG_ERROR,
+				       "P2P: Failed to copy passphrase for GO");
 			wpa_config_remove_network(wpa_s->conf, ssid->id);
 			return;
 		}
@@ -997,6 +1011,27 @@
 	d->max_num_sta = s->max_num_sta;
 	d->pbc_in_m1 = s->pbc_in_m1;
 	d->ignore_old_scan_res = s->ignore_old_scan_res;
+	d->beacon_int = s->beacon_int;
+}
+
+
+static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
+				      char *ifname, size_t len)
+{
+	char *ifname_ptr = wpa_s->ifname;
+
+	if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
+		       os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+		ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
+	}
+
+	os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
+	if (os_strlen(ifname) >= IFNAMSIZ &&
+	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+		/* Try to avoid going over the IFNAMSIZ length limit */
+		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
+			    wpa_s->p2p_group_idx);
+	}
 }
 
 
@@ -1017,14 +1052,7 @@
 		return 0;
 	}
 
-	os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
-		    wpa_s->p2p_group_idx);
-	if (os_strlen(ifname) >= IFNAMSIZ &&
-	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
-		/* Try to avoid going over the IFNAMSIZ length limit */
-		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
-			    wpa_s->p2p_group_idx);
-	}
+	wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
 	force_ifname[0] = '\0';
 
 	wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -1094,7 +1122,13 @@
 	os_memset(&iface, 0, sizeof(iface));
 	iface.ifname = wpa_s->pending_interface_name;
 	iface.driver = wpa_s->driver->name;
-	iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+	if (wpa_s->conf->ctrl_interface == NULL &&
+	    wpa_s->parent != wpa_s &&
+	    wpa_s->p2p_mgmt &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
+		iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
+	else
+		iface.ctrl_interface = wpa_s->conf->ctrl_interface;
 	iface.driver_param = wpa_s->conf->driver_param;
 	group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
 	if (group_wpa_s == NULL) {
@@ -1119,6 +1153,14 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+	wpas_p2p_group_formation_failed(wpa_s);
+}
+
+
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+			     wpa_s->parent, NULL);
 	if (wpa_s->global->p2p)
 		p2p_group_formation_failed(wpa_s->global->p2p);
 	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
@@ -1138,8 +1180,9 @@
 	}
 
 	if (res->status) {
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
-			res->status);
+		wpa_msg_global(wpa_s, MSG_INFO,
+			       P2P_EVENT_GO_NEG_FAILURE "status=%d",
+			       res->status);
 		wpas_notify_p2p_go_neg_completed(wpa_s, res);
 		wpas_p2p_remove_pending_group_interface(wpa_s);
 		return;
@@ -1148,7 +1191,7 @@
 	if (wpa_s->p2p_go_ht40)
 		res->ht40 = 1;
 
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
 	wpas_notify_p2p_go_neg_completed(wpa_s, res);
 
 	if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
@@ -1208,8 +1251,8 @@
 void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
-		" dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+		       " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
 
 	wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
 }
@@ -1232,16 +1275,16 @@
 					WFD_DEV_INFO_SIZE);
 	}
 #endif /* CONFIG_WIFI_DISPLAY */
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
-		" p2p_dev_addr=" MACSTR
-		" pri_dev_type=%s name='%s' config_methods=0x%x "
-		"dev_capab=0x%x group_capab=0x%x%s%s",
-		MAC2STR(addr), MAC2STR(info->p2p_device_addr),
-		wps_dev_type_bin2str(info->pri_dev_type, devtype,
-				     sizeof(devtype)),
-		info->device_name, info->config_methods,
-		info->dev_capab, info->group_capab,
-		wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
+		       " p2p_dev_addr=" MACSTR
+		       " pri_dev_type=%s name='%s' config_methods=0x%x "
+		       "dev_capab=0x%x group_capab=0x%x%s%s",
+		       MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+		       wps_dev_type_bin2str(info->pri_dev_type, devtype,
+					    sizeof(devtype)),
+		       info->device_name, info->config_methods,
+		       info->dev_capab, info->group_capab,
+		       wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
@@ -1252,13 +1295,20 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
-		"p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+		       "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
 
 	wpas_notify_p2p_device_lost(wpa_s, dev_addr);
 }
 
 
+static void wpas_find_stopped(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+}
+
+
 static int wpas_start_listen(void *ctx, unsigned int freq,
 			     unsigned int duration,
 			     const struct wpabuf *probe_resp_ie)
@@ -2267,16 +2317,16 @@
 					 const u8 *peer, const char *params,
 					 unsigned int generated_pin)
 {
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
-		MAC2STR(peer), generated_pin, params);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR
+		       " %08d%s", MAC2STR(peer), generated_pin, params);
 }
 
 
 static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
 					const u8 *peer, const char *params)
 {
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s",
-		MAC2STR(peer), params);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR
+		       "%s", MAC2STR(peer), params);
 }
 
 
@@ -2328,8 +2378,8 @@
 	} else if (config_methods & WPS_CONFIG_KEYPAD)
 		wpas_prov_disc_local_keypad(wpa_s, peer, params);
 	else if (config_methods & WPS_CONFIG_PUSHBUTTON)
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
-			"%s", MAC2STR(peer), params);
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ
+			       MACSTR "%s", MAC2STR(peer), params);
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
 					    P2P_PROV_DISC_SUCCESS,
@@ -2367,8 +2417,8 @@
 		wpas_prov_disc_local_display(wpa_s, peer, params,
 					     generated_pin);
 	} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
-			"%s", MAC2STR(peer), params);
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP
+			       MACSTR "%s", MAC2STR(peer), params);
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
 					    P2P_PROV_DISC_SUCCESS,
@@ -2397,19 +2447,29 @@
 		return;
 	}
 
-	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
-		" p2p_dev_addr=" MACSTR " status=%d",
-		MAC2STR(peer), status);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+		       " p2p_dev_addr=" MACSTR " status=%d",
+		       MAC2STR(peer), status);
 
 	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
 					    status, 0, 0);
 }
 
 
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+	if (channels == NULL)
+		return 1; /* Assume no restrictions */
+	return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
 static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
 				  const u8 *go_dev_addr, const u8 *ssid,
 				  size_t ssid_len, int *go, u8 *group_bssid,
-				  int *force_freq, int persistent_group)
+				  int *force_freq, int persistent_group,
+				  const struct p2p_channels *channels)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
@@ -2507,6 +2567,25 @@
 		wpas_p2p_set_own_freq_preference(wpa_s, res);
 	}
 
+	if (*force_freq > 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		if (*go == 0) {
+			/* We are the client */
+			wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+				   "running a GO but we are capable of MCC, "
+				   "figure out the best channel to use");
+			*force_freq = 0;
+		} else if (!freq_included(channels, *force_freq)) {
+			/* We are the GO, and *force_freq is not in the
+			 * intersection */
+			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+				   "in intersection but we are capable of MCC, "
+				   "figure out the best channel to use",
+				   *force_freq);
+			*force_freq = 0;
+		}
+	}
+
 	return P2P_SC_SUCCESS;
 }
 
@@ -2550,27 +2629,30 @@
 
 	if (!s) {
 		if (bssid) {
-			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
-				"sa=" MACSTR " go_dev_addr=" MACSTR
-				" bssid=" MACSTR " unknown-network",
-				MAC2STR(sa), MAC2STR(go_dev_addr),
-				MAC2STR(bssid));
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_INVITATION_RECEIVED
+				       "sa=" MACSTR " go_dev_addr=" MACSTR
+				       " bssid=" MACSTR " unknown-network",
+				       MAC2STR(sa), MAC2STR(go_dev_addr),
+				       MAC2STR(bssid));
 		} else {
-			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
-				"sa=" MACSTR " go_dev_addr=" MACSTR
-				" unknown-network",
-				MAC2STR(sa), MAC2STR(go_dev_addr));
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_INVITATION_RECEIVED
+				       "sa=" MACSTR " go_dev_addr=" MACSTR
+				       " unknown-network",
+				       MAC2STR(sa), MAC2STR(go_dev_addr));
 		}
 		return;
 	}
 
 	if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
-			MACSTR " persistent=%d freq=%d",
-			MAC2STR(sa), s->id, op_freq);
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+			       "sa=" MACSTR " persistent=%d freq=%d",
+			       MAC2STR(sa), s->id, op_freq);
 	} else {
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
-			MACSTR " persistent=%d", MAC2STR(sa), s->id);
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+			       "sa=" MACSTR " persistent=%d",
+			       MAC2STR(sa), s->id);
 	}
 }
 
@@ -2642,12 +2724,12 @@
 	struct wpa_ssid *ssid;
 
 	if (bssid) {
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
-			"status=%d " MACSTR,
-			status, MAC2STR(bssid));
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+			       "status=%d " MACSTR,
+			       status, MAC2STR(bssid));
 	} else {
-		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
-			"status=%d ", status);
+		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+			       "status=%d ", status);
 	}
 	wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
 
@@ -2988,6 +3070,52 @@
 }
 
 
+static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_msg_global(wpa_s, level, "P2P: %s", msg);
+}
+
+
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_interface iface;
+	struct wpa_supplicant *p2pdev_wpa_s;
+	char ifname[100];
+	char force_name[100];
+	int ret;
+
+	os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+		    wpa_s->ifname);
+	force_name[0] = '\0';
+	wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+	ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+			     force_name, wpa_s->pending_interface_addr, NULL);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+		return ret;
+	}
+	os_strlcpy(wpa_s->pending_interface_name, ifname,
+		   sizeof(wpa_s->pending_interface_name));
+
+	os_memset(&iface, 0, sizeof(iface));
+	iface.p2p_mgmt = 1;
+	iface.ifname = wpa_s->pending_interface_name;
+	iface.driver = wpa_s->driver->name;
+	iface.driver_param = wpa_s->conf->driver_param;
+	iface.confname = wpa_s->confname;
+	p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	if (!p2pdev_wpa_s) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+		return -1;
+	}
+	p2pdev_wpa_s->parent = wpa_s;
+
+	wpa_s->pending_interface_name[0] = '\0';
+	return 0;
+}
+
+
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -3026,8 +3154,8 @@
 	}
 
 	os_memset(&p2p, 0, sizeof(p2p));
-	p2p.msg_ctx = wpa_s;
 	p2p.cb_ctx = wpa_s;
+	p2p.debug_print = wpas_p2p_debug_print;
 	p2p.p2p_scan = wpas_p2p_scan;
 	p2p.send_action = wpas_send_action;
 	p2p.send_action_done = wpas_send_action_done;
@@ -3035,6 +3163,7 @@
 	p2p.go_neg_req_rx = wpas_go_neg_req_rx;
 	p2p.dev_found = wpas_dev_found;
 	p2p.dev_lost = wpas_dev_lost;
+	p2p.find_stopped = wpas_find_stopped;
 	p2p.start_listen = wpas_start_listen;
 	p2p.stop_listen = wpas_stop_listen;
 	p2p.send_probe_resp = wpas_send_probe_resp;
@@ -3096,6 +3225,12 @@
 		wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
 			   "%d:%d", p2p.op_reg_class, p2p.op_channel);
 	}
+
+	if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
+		p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
+		p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
+	}
+
 	if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
 		os_memcpy(p2p.country, wpa_s->conf->country, 2);
 		p2p.country[2] = 0x04;
@@ -3180,6 +3315,9 @@
 
 	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;
@@ -3242,7 +3380,8 @@
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->conf->p2p_no_group_iface)
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+	    wpa_s->conf->p2p_no_group_iface)
 		return 0; /* separate interface disabled per configuration */
 	if (wpa_s->drv_flags &
 	    (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -3322,13 +3461,14 @@
 		eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 		if (wpa_s->p2p_auto_pd) {
 			wpa_s->p2p_auto_pd = 0;
-			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
-				" p2p_dev_addr=" MACSTR " status=N/A",
-				MAC2STR(wpa_s->pending_join_dev_addr));
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_PROV_DISC_FAILURE
+				       " p2p_dev_addr=" MACSTR " status=N/A",
+				       MAC2STR(wpa_s->pending_join_dev_addr));
 			return;
 		}
-		wpa_msg(wpa_s->parent, MSG_INFO,
-			P2P_EVENT_GROUP_FORMATION_FAILURE);
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_GROUP_FORMATION_FAILURE);
 	}
 }
 
@@ -3452,9 +3592,10 @@
 				      wpa_s->pending_pd_config_methods, join,
 				      0, wpa_s->user_initiated_pd) < 0) {
 			wpa_s->p2p_auto_pd = 0;
-			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
-				" p2p_dev_addr=" MACSTR " status=N/A",
-				MAC2STR(wpa_s->pending_join_dev_addr));
+			wpa_msg_global(wpa_s, MSG_INFO,
+				       P2P_EVENT_PROV_DISC_FAILURE
+				       " p2p_dev_addr=" MACSTR " status=N/A",
+				       MAC2STR(wpa_s->pending_join_dev_addr));
 		}
 		return;
 	}
@@ -3516,9 +3657,9 @@
 		u16 method;
 
 		if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
-			wpa_msg(wpa_s->parent, MSG_INFO,
-				P2P_EVENT_GROUP_FORMATION_FAILURE
-				"reason=FREQ_CONFLICT");
+			wpa_msg_global(wpa_s->parent, MSG_INFO,
+				       P2P_EVENT_GROUP_FORMATION_FAILURE
+				       "reason=FREQ_CONFLICT");
 			return;
 		}
 
@@ -4059,11 +4200,57 @@
 }
 
 
-static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
 {
-	if (channels == NULL)
-		return 1; /* Assume no restrictions */
-	return p2p_channels_includes_freq(channels, freq);
+	unsigned int r;
+
+	if (freq == 2) {
+		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+			   "band");
+		if (wpa_s->best_24_freq > 0 &&
+		    p2p_supported_freq(wpa_s->global->p2p,
+				       wpa_s->best_24_freq)) {
+			freq = wpa_s->best_24_freq;
+			wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+				   "channel: %d MHz", freq);
+		} else {
+			os_get_random((u8 *) &r, sizeof(r));
+			freq = 2412 + (r % 3) * 25;
+			wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+				   "channel: %d MHz", freq);
+		}
+	}
+
+	if (freq == 5) {
+		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+			   "band");
+		if (wpa_s->best_5_freq > 0 &&
+		    p2p_supported_freq(wpa_s->global->p2p,
+				       wpa_s->best_5_freq)) {
+			freq = wpa_s->best_5_freq;
+			wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+				   "channel: %d MHz", freq);
+		} else {
+			os_get_random((u8 *) &r, sizeof(r));
+			freq = 5180 + (r % 4) * 20;
+			if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+				wpa_printf(MSG_DEBUG, "P2P: Could not select "
+					   "5 GHz channel for P2P group");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+				   "channel: %d MHz", freq);
+		}
+	}
+
+	if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+			   "(%u MHz) is not supported for P2P uses",
+			   freq);
+		return -1;
+	}
+
+	return freq;
 }
 
 
@@ -4074,6 +4261,7 @@
 {
 	u8 bssid[ETH_ALEN];
 	int res;
+	unsigned int pref_freq;
 
 	os_memset(params, 0, sizeof(*params));
 	params->role_go = 1;
@@ -4130,6 +4318,11 @@
 		params->freq = wpa_s->best_5_freq;
 		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
 			   "channel %d MHz", params->freq);
+	} else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
+						  channels))) {
+		params->freq = pref_freq;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
+			   "channels", params->freq);
 	} else {
 		int chan;
 		for (chan = 0; chan < 11; chan++) {
@@ -4224,13 +4417,14 @@
 
 	if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
 					 WPA_IF_P2P_CLIENT) < 0) {
-		wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to add group interface");
+		wpa_msg_global(wpa_s, MSG_ERROR,
+			       "P2P: Failed to add group interface");
 		return NULL;
 	}
 	group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
 	if (group_wpa_s == NULL) {
-		wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to initialize group "
-			"interface");
+		wpa_msg_global(wpa_s, MSG_ERROR,
+			       "P2P: Failed to initialize group interface");
 		wpas_p2p_remove_pending_group_interface(wpa_s);
 		return NULL;
 	}
@@ -4255,7 +4449,6 @@
 		       int freq, int ht40)
 {
 	struct p2p_go_neg_results params;
-	unsigned int r;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
@@ -4264,51 +4457,9 @@
 	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
 	wpas_p2p_stop_find_oper(wpa_s);
 
-	if (freq == 2) {
-		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
-			   "band");
-		if (wpa_s->best_24_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
-				       wpa_s->best_24_freq)) {
-			freq = wpa_s->best_24_freq;
-			wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
-				   "channel: %d MHz", freq);
-		} else {
-			os_get_random((u8 *) &r, sizeof(r));
-			freq = 2412 + (r % 3) * 25;
-			wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
-				   "channel: %d MHz", freq);
-		}
-	}
-
-	if (freq == 5) {
-		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
-			   "band");
-		if (wpa_s->best_5_freq > 0 &&
-		    p2p_supported_freq(wpa_s->global->p2p,
-				       wpa_s->best_5_freq)) {
-			freq = wpa_s->best_5_freq;
-			wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
-				   "channel: %d MHz", freq);
-		} else {
-			os_get_random((u8 *) &r, sizeof(r));
-			freq = 5180 + (r % 4) * 20;
-			if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
-				wpa_printf(MSG_DEBUG, "P2P: Could not select "
-					   "5 GHz channel for P2P group");
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
-				   "channel: %d MHz", freq);
-		}
-	}
-
-	if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
-		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
-			   "(%u MHz) is not supported for P2P uses",
-			   freq);
+	freq = wpas_p2p_select_go_freq(wpa_s, freq);
+	if (freq < 0)
 		return -1;
-	}
 
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
 		return -1;
@@ -4404,6 +4555,10 @@
 	if (ssid->mode != WPAS_MODE_P2P_GO)
 		return -1;
 
+	freq = wpas_p2p_select_go_freq(wpa_s, freq);
+	if (freq < 0)
+		return -1;
+
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
 		return -1;
 
@@ -5034,20 +5189,20 @@
 	if (ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
-		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-			"%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
-			MACSTR "%s",
-			wpa_s->ifname, ssid_txt, freq, psk,
-			MAC2STR(go_dev_addr),
-			persistent ? " [PERSISTENT]" : "");
+		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			       "%s client ssid=\"%s\" freq=%d psk=%s "
+			       "go_dev_addr=" MACSTR "%s",
+			       wpa_s->ifname, ssid_txt, freq, psk,
+			       MAC2STR(go_dev_addr),
+			       persistent ? " [PERSISTENT]" : "");
 	} else {
-		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-			"%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
-			"go_dev_addr=" MACSTR "%s",
-			wpa_s->ifname, ssid_txt, freq,
-			ssid->passphrase ? ssid->passphrase : "",
-			MAC2STR(go_dev_addr),
-			persistent ? " [PERSISTENT]" : "");
+		wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			       "%s client ssid=\"%s\" freq=%d "
+			       "passphrase=\"%s\" go_dev_addr=" MACSTR "%s",
+			       wpa_s->ifname, ssid_txt, freq,
+			       ssid->passphrase ? ssid->passphrase : "",
+			       MAC2STR(go_dev_addr),
+			       persistent ? " [PERSISTENT]" : "");
 	}
 
 	if (persistent)
@@ -5379,9 +5534,10 @@
 
 			iface->cross_connect_enabled = 0;
 			iface->cross_connect_in_use = 0;
-			wpa_msg(iface->parent, MSG_INFO,
-				P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
-				iface->ifname, iface->cross_connect_uplink);
+			wpa_msg_global(iface->parent, MSG_INFO,
+				       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+				       iface->ifname,
+				       iface->cross_connect_uplink);
 		}
 	}
 
@@ -5408,9 +5564,9 @@
 			continue;
 
 		iface->cross_connect_in_use = 1;
-		wpa_msg(iface->parent, MSG_INFO,
-			P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
-			iface->ifname, iface->cross_connect_uplink);
+		wpa_msg_global(iface->parent, MSG_INFO,
+			       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+			       iface->ifname, iface->cross_connect_uplink);
 	}
 }
 
@@ -5428,9 +5584,9 @@
 		if (!iface->cross_connect_in_use)
 			continue;
 
-		wpa_msg(iface->parent, MSG_INFO,
-			P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
-			iface->ifname, iface->cross_connect_uplink);
+		wpa_msg_global(iface->parent, MSG_INFO,
+			       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+			       iface->ifname, iface->cross_connect_uplink);
 		iface->cross_connect_in_use = 0;
 	}
 }
@@ -5490,9 +5646,9 @@
 			break;
 
 		wpa_s->cross_connect_in_use = 1;
-		wpa_msg(wpa_s->parent, MSG_INFO,
-			P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
-			wpa_s->ifname, wpa_s->cross_connect_uplink);
+		wpa_msg_global(wpa_s->parent, MSG_INFO,
+			       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+			       wpa_s->ifname, wpa_s->cross_connect_uplink);
 		break;
 	}
 }
@@ -5508,14 +5664,7 @@
 		   "session overlap");
 	if (wpa_s != wpa_s->parent)
 		wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
-
-	if (wpa_s->global->p2p)
-		p2p_group_formation_failed(wpa_s->global->p2p);
-
-	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-			     wpa_s->parent, NULL);
-
-	wpas_group_formation_completed(wpa_s, 0);
+	wpas_p2p_group_formation_failed(wpa_s);
 	return 1;
 }
 
@@ -5858,6 +6007,14 @@
 }
 
 #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);
+}
+
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
 	struct wpa_ssid *ssid)
 {
@@ -5890,7 +6047,8 @@
 				 * P2P connection. So remove the interface */
 				wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
 						"concurrent mode frequency conflict");
-				wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_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;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 04ba9b2..3ca6222 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -14,10 +14,12 @@
 enum p2p_send_action_result;
 struct p2p_peer_info;
 struct p2p_channels;
+struct wps_event_fail;
 
 int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		     const char *pin, enum p2p_wps_method wps_method,
 		     int persistent_group, int auto_join, int join,
@@ -76,6 +78,7 @@
 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,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index db73a18..8cd0f1d 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -453,6 +453,11 @@
 
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
+		wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
 	return extra_ie;
 }
 
@@ -481,6 +486,7 @@
 	return 0;
 }
 
+#endif /* CONFIG_P2P */
 
 /*
  * Find the operating frequency of any other virtual interface that is using
@@ -520,7 +526,62 @@
 	return 0;
 }
 
-#endif /* CONFIG_P2P */
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+					  u16 num_modes,
+					  enum hostapd_hw_mode mode)
+{
+	u16 i;
+
+	for (i = 0; i < num_modes; i++) {
+		if (modes[i].mode == mode)
+			return &modes[i];
+	}
+
+	return NULL;
+}
+
+
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+					enum hostapd_hw_mode band,
+					struct wpa_driver_scan_params *params)
+{
+	/* Include only supported channels for the specified band */
+	struct hostapd_hw_modes *mode;
+	int count, i;
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+	if (mode == NULL) {
+		/* No channels supported in this band - use empty list */
+		params->freqs = os_zalloc(sizeof(int));
+		return;
+	}
+
+	params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	for (count = 0, i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		params->freqs[count++] = mode->channels[i].freq;
+	}
+}
+
+
+static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+				   struct wpa_driver_scan_params *params)
+{
+	if (wpa_s->hw.modes == NULL)
+		return; /* unknown what channels the driver supports */
+	if (params->freqs)
+		return; /* already using a limited channel set */
+	if (wpa_s->setband == WPA_SETBAND_5G)
+		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+					    params);
+	else if (wpa_s->setband == WPA_SETBAND_2G)
+		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+					    params);
+}
 
 
 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
@@ -576,7 +637,7 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpas_p2p_in_progress(wpa_s)) {
+	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) {
@@ -749,11 +810,6 @@
 	wpa_supplicant_optimize_freqs(wpa_s, &params);
 	extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
-#ifdef CONFIG_HS20
-	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
-		wpas_hs20_add_indication(extra_ie);
-#endif /* CONFIG_HS20 */
-
 	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
 			"generated frequency list");
@@ -761,6 +817,27 @@
 	} else
 		os_free(wpa_s->next_scan_freqs);
 	wpa_s->next_scan_freqs = NULL;
+	wpa_setband_scan_freqs(wpa_s, &params);
+
+	/* See if user specified frequencies. If so, scan only those. */
+	if (wpa_s->conf->freq_list && !params.freqs) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Optimize scan based on conf->freq_list");
+		int_array_concat(&params.freqs, wpa_s->conf->freq_list);
+	}
+
+	/* Use current associated channel? */
+	if (wpa_s->conf->scan_cur_freq && !params.freqs) {
+		int freq = shared_vif_oper_freq(wpa_s);
+		if (freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current "
+				"operating channel (%d MHz) since "
+				"scan_cur_freq is enabled", freq);
+			params.freqs = os_zalloc(sizeof(int) * 2);
+			if (params.freqs)
+				params.freqs[0] = freq;
+		}
+	}
 
 	params.filter_ssids = wpa_supplicant_build_filter_ssids(
 		wpa_s->conf, &params.num_filter_ssids);
@@ -1028,7 +1105,9 @@
 
 	if (!ssid || !wpa_s->prev_sched_ssid) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
-
+		if (wpa_s->conf->sched_scan_interval)
+			wpa_s->sched_scan_interval =
+				wpa_s->conf->sched_scan_interval;
 		if (wpa_s->sched_scan_interval == 0)
 			wpa_s->sched_scan_interval = 10;
 		wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
@@ -1115,6 +1194,8 @@
 			wpa_s->sched_scan_interval);
 	}
 
+	wpa_setband_scan_freqs(wpa_s, scan_params);
+
 	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
 					      wpa_s->sched_scan_interval);
 	wpabuf_free(extra_ie);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 4c78161..0371628 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -353,7 +353,7 @@
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_HS20
-	if (wpa_s->conf->hs20) {
+	if (is_hs20_network(wpa_s, ssid, bss)) {
 		struct wpabuf *hs20;
 		hs20 = wpabuf_alloc(20);
 		if (hs20) {
@@ -942,39 +942,6 @@
 }
 
 
-/**
- * enum wpas_band - Frequency band
- * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
- * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
- */
-enum wpas_band {
-	WPAS_BAND_2GHZ,
-	WPAS_BAND_5GHZ,
-	WPAS_BAND_INVALID
-};
-
-/**
- * freq_to_channel - Convert frequency into channel info
- * @channel: Buffer for returning channel number
- * Returns: Band (2 or 5 GHz)
- */
-static enum wpas_band freq_to_channel(int freq, u8 *channel)
-{
-	enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
-	u8 chan = 0;
-
-	if (freq >= 2412 && freq <= 2472)
-		chan = (freq - 2407) / 5;
-	else if (freq == 2484)
-		chan = 14;
-	else if (freq >= 5180 && freq <= 5805)
-		chan = (freq - 5000) / 5;
-
-	*channel = chan;
-	return band;
-}
-
-
 int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_bss *bss;
@@ -1011,7 +978,10 @@
 
 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
 		/* Skip other band bss */
-		if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ)
+		enum hostapd_hw_mode mode;
+		mode = ieee80211_freq_to_chan(bss->freq, &channel);
+		if (mode != HOSTAPD_MODE_IEEE80211G &&
+		    mode != HOSTAPD_MODE_IEEE80211B)
 			continue;
 
 		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 76aba12..bfdee25 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -10,4 +10,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index ff384ae..20ba0ad 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -10,4 +10,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index c215567..10e62bc 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -10,4 +10,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant@wlan0.service
+Alias=multi-user.target.wants/wpa_supplicant@%i.service
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4d9e453..4f8d895 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - 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.
@@ -10,12 +10,17 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "scan.h"
+#include "ctrl_iface.h"
+#include "bss.h"
+#include "wnm_sta.h"
 
 #define MAX_TFS_IE_LEN  1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
 
 
 /* get the TFS IE from driver */
@@ -294,9 +299,203 @@
 }
 
 
-static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
-					      u8 dialog_token, u8 status,
-					      u8 delay, const u8 *target_bssid)
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+	int i;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].bearing);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+	}
+
+	os_free(wpa_s->wnm_neighbor_report_elements);
+	wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+					   u8 id, u8 elen, const u8 *pos)
+{
+	switch (id) {
+	case WNM_NEIGHBOR_TSF:
+		if (elen < 2 + 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+			break;
+		}
+		rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
+		if (rep->tsf_info == NULL)
+			break;
+		rep->tsf_info->present = 1;
+		os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
+		os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+		break;
+	case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+		if (elen < 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+				   "country string");
+			break;
+		}
+		rep->con_coun_str =
+			os_zalloc(sizeof(struct condensed_country_string));
+		if (rep->con_coun_str == NULL)
+			break;
+		rep->con_coun_str->present = 1;
+		os_memcpy(rep->con_coun_str->country_string, pos, 2);
+		break;
+	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+		if (elen < 1) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+				   "candidate");
+			break;
+		}
+		rep->bss_tran_can =
+			os_zalloc(sizeof(struct bss_transition_candidate));
+		if (rep->bss_tran_can == NULL)
+			break;
+		rep->bss_tran_can->present = 1;
+		rep->bss_tran_can->preference = pos[0];
+		break;
+	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+		if (elen < 12) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
+				   "duration");
+			break;
+		}
+		rep->bss_term_dur =
+			os_zalloc(sizeof(struct bss_termination_duration));
+		if (rep->bss_term_dur == NULL)
+			break;
+		rep->bss_term_dur->present = 1;
+		os_memcpy(rep->bss_term_dur->duration, pos, 12);
+		break;
+	case WNM_NEIGHBOR_BEARING:
+		if (elen < 8) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+				   "bearing");
+			break;
+		}
+		rep->bearing = os_zalloc(sizeof(struct bearing));
+		if (rep->bearing == NULL)
+			break;
+		rep->bearing->present = 1;
+		os_memcpy(rep->bearing->bearing, pos, 8);
+		break;
+	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+		if (elen < 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+				   "pilot");
+			break;
+		}
+		rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+		if (rep->meas_pilot == NULL)
+			break;
+		rep->meas_pilot->present = 1;
+		rep->meas_pilot->measurement_pilot = pos[0];
+		rep->meas_pilot->num_vendor_specific = pos[1];
+		os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2);
+		break;
+	case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+		if (elen < 4) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+				   "capabilities");
+			break;
+		}
+		rep->rrm_cap =
+			os_zalloc(sizeof(struct rrm_enabled_capabilities));
+		if (rep->rrm_cap == NULL)
+			break;
+		rep->rrm_cap->present = 1;
+		os_memcpy(rep->rrm_cap->capabilities, pos, 4);
+		break;
+	case WNM_NEIGHBOR_MULTIPLE_BSSID:
+		if (elen < 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+			break;
+		}
+		rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+		if (rep->mul_bssid == NULL)
+			break;
+		rep->mul_bssid->present = 1;
+		rep->mul_bssid->max_bssid_indicator = pos[0];
+		rep->mul_bssid->num_vendor_specific = pos[1];
+		os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2);
+		break;
+	}
+}
+
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+				      const u8 *pos, u8 len,
+				      struct neighbor_report *rep)
+{
+	u8 left = len;
+
+	if (left < 13) {
+		wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+		return;
+	}
+
+	os_memcpy(rep->bssid, pos, ETH_ALEN);
+	os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+	rep->regulatory_class = *(pos + 10);
+	rep->channel_number = *(pos + 11);
+	rep->phy_type = *(pos + 12);
+
+	pos += 13;
+	left -= 13;
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+		left -= 2 + elen;
+		pos += elen;
+	}
+}
+
+
+static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
+					 struct wpa_scan_results *scan_res,
+					 struct neighbor_report *neigh_rep,
+					 u8 num_neigh_rep, u8 *bssid_to_connect)
+{
+
+	u8 i, j;
+
+	if (scan_res == NULL || num_neigh_rep == 0)
+		return 0;
+
+	for (i = 0; i < num_neigh_rep; i++) {
+		for (j = 0; j < scan_res->num; j++) {
+			/* Check for a better RSSI AP */
+			if (os_memcmp(scan_res->res[j]->bssid,
+				      neigh_rep[i].bssid, ETH_ALEN) == 0 &&
+			    scan_res->res[j]->level >
+			    wpa_s->current_bss->level) {
+				/* Got a BSSID with better RSSI value */
+				os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
+					  ETH_ALEN);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static void wnm_send_bss_transition_mgmt_resp(
+	struct wpa_supplicant *wpa_s, u8 dialog_token,
+	enum bss_trans_mgmt_status_code status, u8 delay,
+	const u8 *target_bssid)
 {
 	u8 buf[1000], *pos;
 	struct ieee80211_mgmt *mgmt;
@@ -332,30 +531,93 @@
 }
 
 
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res)
+{
+	u8 bssid[ETH_ALEN];
+
+	if (scan_res == NULL) {
+		wpa_printf(MSG_ERROR, "Scan result is NULL");
+		goto send_bss_resp_fail;
+	}
+
+	/* Compare the Neighbor Report and scan results */
+	if (compare_scan_neighbor_results(wpa_s, scan_res,
+					  wpa_s->wnm_neighbor_report_elements,
+					  wpa_s->wnm_num_neighbor_report,
+					  bssid) == 1) {
+		/* Associate to the network */
+		struct wpa_bss *bss;
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+		if (!bss) {
+			wpa_printf(MSG_DEBUG, "WNM: Target AP not found from "
+				   "BSS table");
+			goto send_bss_resp_fail;
+		}
+
+		/* Send the BSS Management Response - Accept */
+		if (wpa_s->wnm_reply) {
+			wnm_send_bss_transition_mgmt_resp(wpa_s,
+						  wpa_s->wnm_dialog_token,
+						  WNM_BSS_TM_ACCEPT,
+						  0, NULL);
+		}
+
+		wpa_s->reassociate = 1;
+		wpa_supplicant_connect(wpa_s, bss, ssid);
+		wnm_deallocate_memory(wpa_s);
+		return;
+	}
+
+	/* Send reject response for all the failures */
+send_bss_resp_fail:
+	wnm_deallocate_memory(wpa_s);
+	if (wpa_s->wnm_reply) {
+		wnm_send_bss_transition_mgmt_resp(wpa_s,
+						  wpa_s->wnm_dialog_token,
+						  WNM_BSS_TM_REJECT_UNSPECIFIED,
+						  0, NULL);
+	}
+	return;
+}
+
+
 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 					     const u8 *pos, const u8 *end,
 					     int reply)
 {
-	u8 dialog_token;
-	u8 mode;
-	u16 disassoc_timer;
-
 	if (pos + 5 > end)
 		return;
 
-	dialog_token = pos[0];
-	mode = pos[1];
-	disassoc_timer = WPA_GET_LE16(pos + 2);
+	wpa_s->wnm_dialog_token = pos[0];
+	wpa_s->wnm_mode = pos[1];
+	wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+	wpa_s->wnm_validity_interval = pos[4];
+	wpa_s->wnm_reply = reply;
 
 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
 		   "dialog_token=%u request_mode=0x%x "
 		   "disassoc_timer=%u validity_interval=%u",
-		   dialog_token, mode, disassoc_timer, pos[4]);
+		   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+		   wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+
 	pos += 5;
-	if (mode & 0x08)
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+		if (pos + 12 > end) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+			return;
+		}
+		os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
 		pos += 12; /* BSS Termination Duration */
-	if (mode & 0x10) {
+	}
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
 		char url[256];
+		unsigned int beacon_int;
+
 		if (pos + 1 > end || pos + 1 + pos[0] > end) {
 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
 				   "Management Request (URL)");
@@ -363,14 +625,22 @@
 		}
 		os_memcpy(url, pos + 1, pos[0]);
 		url[pos[0]] = '\0';
-		wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
-			"session_info_url=%s", url);
+		pos += 1 + pos[0];
+
+		if (wpa_s->current_bss)
+			beacon_int = wpa_s->current_bss->beacon_int;
+		else
+			beacon_int = 100; /* best guess */
+
+		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+			wpa_sm_pmf_enabled(wpa_s->wpa),
+			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
 	}
 
-	if (mode & 0x04) {
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
 		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
-			"Disassociation Timer %u", disassoc_timer);
-		if (disassoc_timer && !wpa_s->scanning) {
+			"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+		if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
 			/* TODO: mark current BSS less preferred for
 			 * selection */
 			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
@@ -378,15 +648,89 @@
 		}
 	}
 
-	if (reply) {
-		/* TODO: add support for reporting Accept */
-		wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
-						  1 /* Reject - unspecified */,
-						  0, NULL);
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+		wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+		wpa_s->wnm_num_neighbor_report = 0;
+		os_free(wpa_s->wnm_neighbor_report_elements);
+		wpa_s->wnm_neighbor_report_elements = os_zalloc(
+			WNM_MAX_NEIGHBOR_REPORT *
+			sizeof(struct neighbor_report));
+		if (wpa_s->wnm_neighbor_report_elements == NULL)
+			return;
+
+		while (pos + 2 <= end &&
+		       wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+		{
+			u8 tag = *pos++;
+			u8 len = *pos++;
+
+			wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+				   tag);
+			if (pos + len > end) {
+				wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+				return;
+			}
+			wnm_parse_neighbor_report(
+				wpa_s, pos, len,
+				&wpa_s->wnm_neighbor_report_elements[
+					wpa_s->wnm_num_neighbor_report]);
+
+			pos += len;
+			wpa_s->wnm_num_neighbor_report++;
+		}
+
+		wpa_s->scan_res_handler = wnm_scan_response;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	} else if (reply) {
+		enum bss_trans_mgmt_status_code status;
+		if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+			status = WNM_BSS_TM_ACCEPT;
+		else {
+			wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
+			status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+		}
+		wnm_send_bss_transition_mgmt_resp(wpa_s,
+						  wpa_s->wnm_dialog_token,
+						  status, 0, NULL);
 	}
 }
 
 
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+				       u8 query_reason)
+{
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t len;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+		   MACSTR " query_reason=%u",
+		   MAC2STR(wpa_s->bssid), query_reason);
+
+	mgmt = (struct ieee80211_mgmt *) buf;
+	os_memset(&buf, 0, sizeof(buf));
+	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
+	mgmt->u.action.u.bss_tm_query.dialog_token = 0;
+	mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
+	pos = mgmt->u.action.u.bss_tm_query.variable;
+
+	len = pos - (u8 *) &mgmt->u.action.category;
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  &mgmt->u.action.category, len, 0);
+
+	return ret;
+}
+
+
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
 			      struct rx_action *action)
 {
@@ -418,6 +762,7 @@
 		ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
 		break;
 	default:
+		wpa_printf(MSG_ERROR, "WNM: Unknown request");
 		break;
 	}
 }
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 3f9d88b..2933926 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -12,10 +12,79 @@
 struct rx_action;
 struct wpa_supplicant;
 
+struct tsf_info {
+	u8 present;
+	u8 tsf_offset[2];
+	u8 beacon_interval[2];
+};
+
+struct condensed_country_string {
+	u8 present;
+	u8 country_string[2];
+};
+
+struct bss_transition_candidate {
+	u8 present;
+	u8 preference;
+};
+
+struct bss_termination_duration {
+	u8 present;
+	u8 duration[12];
+};
+
+struct bearing {
+	u8 present;
+	u8 bearing[8];
+};
+
+struct measurement_pilot {
+	u8 present;
+	u8 measurement_pilot;
+	u8 num_vendor_specific;
+	u8 vendor_specific[255];
+};
+
+struct rrm_enabled_capabilities {
+	u8 present;
+	u8 capabilities[4];
+};
+
+struct multiple_bssid {
+	u8 present;
+	u8 max_bssid_indicator;
+	u8 num_vendor_specific;
+	u8 vendor_specific[255];
+};
+
+struct neighbor_report {
+	u8 bssid[ETH_ALEN];
+	u8 bssid_information[4];
+	u8 regulatory_class;
+	u8 channel_number;
+	u8 phy_type;
+	struct tsf_info *tsf_info;
+	struct condensed_country_string *con_coun_str;
+	struct bss_transition_candidate *bss_tran_can;
+	struct bss_termination_duration *bss_term_dur;
+	struct bearing *bearing;
+	struct measurement_pilot *meas_pilot;
+	struct rrm_enabled_capabilities *rrm_cap;
+	struct multiple_bssid *mul_bssid;
+};
+
+
 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
 				 u8 action, u16 intval, struct wpabuf *tfs_req);
 
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
 			      struct rx_action *action);
 
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+				       u8 query_reason);
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
 #endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index cdbe011..ba1f207 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2012, 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.
@@ -81,9 +81,7 @@
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
-#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
-static char* redirect_interface = NULL;
-#endif
+static char *ifname_prefix = NULL;
 
 struct cli_txt_entry {
 	struct dl_list list;
@@ -93,6 +91,7 @@
 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
 
 
 static void print_help(const char *cmd);
@@ -176,11 +175,9 @@
 	end = os_strchr(txt, ' ');
 	if (end == NULL)
 		end = txt + os_strlen(txt);
-	buf = os_malloc(end - txt + 1);
+	buf = dup_binstr(txt, end - txt);
 	if (buf == NULL)
 		return;
-	os_memcpy(buf, txt, end - txt);
-	buf[end - txt] = '\0';
 	cli_txt_list_del(txt_list, buf);
 	os_free(buf);
 }
@@ -226,11 +223,9 @@
 	end = os_strchr(txt, ' ');
 	if (end == NULL)
 		end = txt + os_strlen(txt);
-	buf = os_malloc(end - txt + 1);
+	buf = dup_binstr(txt, end - txt);
 	if (buf == NULL)
 		return -1;
-	os_memcpy(buf, txt, end - txt);
-	buf[end - txt] = '\0';
 	ret = cli_txt_list_add(txt_list, buf);
 	os_free(buf);
 	return ret;
@@ -404,9 +399,6 @@
 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
 {
 	char buf[4096];
-#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
-	char _cmd[256];
-#endif
 	size_t len;
 	int ret;
 
@@ -414,22 +406,12 @@
 		printf("Not connected to wpa_supplicant - command dropped.\n");
 		return -1;
 	}
-#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
-	if (redirect_interface) {
-		char *arg;
-		arg = os_strchr(cmd, ' ');
-		if (arg) {
-			*arg++ = '\0';
-			ret = os_snprintf(_cmd, sizeof(_cmd), "%s %s %s", cmd, redirect_interface, arg);
-		}
-		else {
-			ret = os_snprintf(_cmd, sizeof(_cmd), "%s %s", cmd, redirect_interface);
-		}
-		cmd = _cmd;
-		os_free(redirect_interface);
-		redirect_interface = NULL;
+	if (ifname_prefix) {
+		os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+			    ifname_prefix, cmd);
+		buf[sizeof(buf) - 1] = '\0';
+		cmd = buf;
 	}
-#endif
 	len = sizeof(buf) - 1;
 	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
 			       wpa_cli_msg_cb);
@@ -489,7 +471,7 @@
 static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
 		       int argc, char *argv[])
 {
-	char buf[256];
+	char buf[4096];
 	if (argc < min_args) {
 		printf("Invalid %s command - at least %d argument%s "
 		       "required.\n", cmd, min_args,
@@ -586,52 +568,81 @@
 }
 
 
-static void wpa_cli_show_variables(void)
-{
-	printf("set variables:\n"
-	       "  EAPOL::heldPeriod (EAPOL state machine held period, "
-	       "in seconds)\n"
-	       "  EAPOL::authPeriod (EAPOL state machine authentication "
-	       "period, in seconds)\n"
-	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
-	       "seconds)\n"
-	       "  EAPOL::maxStart (EAPOL state machine maximum start "
-	       "attempts)\n");
-	printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
-	       "seconds)\n"
-	       "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
-	       " threshold\n\tpercentage)\n"
-	       "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
-	       "security\n\tassociation in seconds)\n");
-}
-
-
 static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char cmd[256];
 	int res;
 
-	if (argc == 0) {
-		wpa_cli_show_variables();
-		return 0;
-	}
-
-	if (argc != 1 && argc != 2) {
-		printf("Invalid SET command: needs two arguments (variable "
-		       "name and value)\n");
-		return -1;
-	}
-
-	if (argc == 1)
+	if (argc == 1) {
 		res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
-	else
-		res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
-				  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long SET command.\n");
-		return -1;
+		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+			printf("Too long SET command.\n");
+			return -1;
+		}
+		return wpa_ctrl_command(ctrl, cmd);
 	}
-	return wpa_ctrl_command(ctrl, cmd);
+
+	return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_set(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	const char *fields[] = {
+		/* runtime values */
+		"EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
+		"EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
+		"dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
+		"wps_fragment_size", "wps_version_number", "ampdu",
+		"tdls_testing", "tdls_disabled", "pno", "radio_disabled",
+		"uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
+		"no_keep_alive",
+		/* global configuration parameters */
+		"eapol_version", "ap_scan", "disable_scan_offload",
+		"fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
+		"pkcs11_module_path", "pcsc_reader", "pcsc_pin",
+		"driver_param", "dot11RSNAConfigPMKLifetime",
+		"dot11RSNAConfigPMKReauthThreshold",
+		"dot11RSNAConfigSATimeout",
+		"update_config", "load_dynamic_eap", "uuid", "device_name",
+		"manufacturer", "model_name", "model_number", "serial_number",
+		"device_type", "os_version", "config_methods",
+		"wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+		"p2p_listen_reg_class", "p2p_listen_channel",
+		"p2p_oper_reg_class", "p2p_oper_channel",
+		"p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
+		"p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+		"p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+		"p2p_ignore_shared_freq", "country", "bss_max_count",
+		"bss_expiration_age", "bss_expiration_scan_count",
+		"filter_ssids", "filter_rssi", "max_num_sta",
+		"disassoc_low_ack", "hs20", "interworking", "hessid",
+		"access_network_type", "pbc_in_m1", "autoscan",
+		"wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
+		"wps_nfc_dev_pw", "ext_password_backend",
+		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+		"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
+		"ignore_old_scan_res", "freq_list"
+	};
+	int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+
+	if (arg == 1) {
+		char **res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(fields[i]);
+			if (res[i] == NULL)
+				return res;
+		}
+		return res;
+	}
+
+	if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
+		return cli_txt_list_array(&bsses);
+
+	return NULL;
 }
 
 
@@ -2290,6 +2301,12 @@
 	return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
 }
 
+
+static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
+}
+
 #endif /* CONFIG_WNM */
 
 
@@ -2376,7 +2393,7 @@
 	{ "quit", wpa_cli_cmd_quit, NULL,
 	  cli_cmd_flag_none,
 	  "= exit wpa_cli" },
-	{ "set", wpa_cli_cmd_set, NULL,
+	{ "set", wpa_cli_cmd_set, wpa_cli_complete_set,
 	  cli_cmd_flag_none,
 	  "= set variables (shows list of variables when run without "
 	  "arguments)" },
@@ -2489,7 +2506,7 @@
 	  "<<idx> | <bssid>> = get detailed scan result info" },
 	{ "get_capability", wpa_cli_cmd_get_capability, NULL,
 	  cli_cmd_flag_none,
-	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/modes> "
+	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
 	  "= get capabilies" },
 	{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
 	  cli_cmd_flag_none,
@@ -2773,6 +2790,8 @@
 #ifdef CONFIG_WNM
 	{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
 	  "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
+	{ "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
+	  "<query reason> = Send BSS Transition Management Query" },
 #endif /* CONFIG_WNM */
 	{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
 	  "<params..> = Sent unprocessed command" },
@@ -2841,9 +2860,12 @@
 {
 	char **res;
 	int i, count;
+	struct cli_txt_entry *e;
 
 	count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
-	res = os_calloc(count, sizeof(char *));
+	count += dl_list_len(&p2p_groups);
+	count += dl_list_len(&ifnames);
+	res = os_calloc(count + 1, sizeof(char *));
 	if (res == NULL)
 		return NULL;
 
@@ -2853,6 +2875,22 @@
 			break;
 	}
 
+	dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+		size_t len = 8 + os_strlen(e->txt);
+		res[i] = os_malloc(len);
+		if (res[i] == NULL)
+			break;
+		os_snprintf(res[i], len, "ifname=%s", e->txt);
+		i++;
+	}
+
+	dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+		res[i] = os_strdup(e->txt);
+		if (res[i] == NULL)
+			break;
+		i++;
+	}
+
 	return res;
 }
 
@@ -2884,6 +2922,14 @@
 	const char *end;
 	char *cmd;
 
+	if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+		end = os_strchr(str, ' ');
+		if (end && pos > end - str) {
+			pos -= end - str + 1;
+			str = end + 1;
+		}
+	}
+
 	end = os_strchr(str, ' ');
 	if (end == NULL || str + pos < end)
 		return wpa_list_cmd_list();
@@ -2905,6 +2951,16 @@
 	int count;
 	int ret = 0;
 
+	if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+		ifname_prefix = argv[0] + 7;
+		argv = &argv[1];
+		argc--;
+	} else
+		ifname_prefix = NULL;
+
+	if (argc == 0)
+		return -1;
+
 	count = 0;
 	cmd = wpa_cli_commands;
 	while (cmd->cmd) {
@@ -2937,13 +2993,6 @@
 		printf("Unknown command '%s'\n", argv[0]);
 		ret = 1;
 	} else {
-#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
-		if ( (argc >= 2) && (os_strncmp(argv[1], "interface=", 10) == 0)) {
-			redirect_interface = os_strdup(argv[1]);
-			ret = match->handler(ctrl, argc - 2, &argv[2]);
-		}
-		else
-#endif
 		ret = match->handler(ctrl, argc - 1, &argv[1]);
 	}
 
@@ -3059,6 +3108,8 @@
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
 		wpa_cli_quit = 1;
@@ -3320,8 +3371,74 @@
 }
 
 
+static void update_bssid_list(struct wpa_ctrl *ctrl)
+{
+	char buf[4096];
+	size_t len = sizeof(buf);
+	int ret;
+	char *cmd = "BSS RANGE=ALL MASK=0x2";
+	char *pos, *end;
+
+	if (ctrl == NULL)
+		return;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+	if (ret < 0)
+		return;
+	buf[len] = '\0';
+
+	pos = buf;
+	while (pos) {
+		pos = os_strstr(pos, "bssid=");
+		if (pos == NULL)
+			break;
+		pos += 6;
+		end = os_strchr(pos, '\n');
+		if (end == NULL)
+			break;
+		*end = '\0';
+		cli_txt_list_add(&bsses, pos);
+		pos = end + 1;
+	}
+}
+
+
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+	char buf[4096];
+	size_t len = sizeof(buf);
+	int ret;
+	char *cmd = "INTERFACES";
+	char *pos, *end;
+	char txt[200];
+
+	cli_txt_list_flush(&ifnames);
+
+	if (ctrl == NULL)
+		return;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+	if (ret < 0)
+		return;
+	buf[len] = '\0';
+
+	pos = buf;
+	while (pos) {
+		end = os_strchr(pos, '\n');
+		if (end == NULL)
+			break;
+		*end = '\0';
+		ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+		if (ret > 0 && ret < (int) sizeof(txt))
+			cli_txt_list_add(&ifnames, txt);
+		pos = end + 1;
+	}
+}
+
+
 static void try_connection(void *eloop_ctx, void *timeout_ctx)
 {
+	if (ctrl_conn)
+		goto done;
+
 	if (ctrl_ifname == NULL)
 		ctrl_ifname = wpa_cli_get_default_ifname();
 
@@ -3335,9 +3452,12 @@
 		return;
 	}
 
+	update_bssid_list(ctrl_conn);
+
 	if (warning_displayed)
 		printf("Connection established.\n");
 
+done:
 	start_edit();
 }
 
@@ -3353,6 +3473,7 @@
 	cli_txt_list_flush(&p2p_peers);
 	cli_txt_list_flush(&p2p_groups);
 	cli_txt_list_flush(&bsses);
+	cli_txt_list_flush(&ifnames);
 	if (edit_started)
 		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
 	os_free(hfile);
@@ -3459,7 +3580,7 @@
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-	char buf[2048], *pos;
+	char buf[4096], *pos;
 	size_t len;
 	struct wpa_ctrl *ctrl;
 	int ret;
@@ -3553,6 +3674,24 @@
 				global, strerror(errno));
 			return -1;
 		}
+
+		if (interactive) {
+			update_ifnames(ctrl_conn);
+			mon_conn = wpa_ctrl_open(global);
+			if (mon_conn) {
+				if (wpa_ctrl_attach(mon_conn) == 0) {
+					wpa_cli_attached = 1;
+					eloop_register_read_sock(
+						wpa_ctrl_get_fd(mon_conn),
+						wpa_cli_mon_receive,
+						NULL, NULL);
+				} else {
+					printf("Failed to open monitor "
+					       "connection through global "
+					       "control interface\n");
+				}
+			}
+		}
 	}
 
 	eloop_register_signal_terminate(wpa_cli_terminate, NULL);
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index ad6a080..4afaae9 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -573,13 +573,11 @@
 	iface->fd = -1;
 
 	len = pos - params;
-	iface->driver_name = os_malloc(len + 1);
+	iface->driver_name = dup_binstr(params, len);
 	if (iface->driver_name == NULL) {
 		wpa_priv_interface_deinit(iface);
 		return NULL;
 	}
-	os_memcpy(iface->driver_name, params, len);
-	iface->driver_name[len] = '\0';
 
 	for (i = 0; wpa_drivers[i]; i++) {
 		if (os_strcmp(iface->driver_name,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index a9a939b..f6b881b 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -17,6 +17,7 @@
 #include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
 #include "eap_server/eap_methods.h"
 #include "rsn_supp/wpa.h"
 #include "eloop.h"
@@ -49,6 +50,7 @@
 #include "scan.h"
 #include "offchannel.h"
 #include "hs20_supplicant.h"
+#include "wnm_sta.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -126,8 +128,8 @@
 }
 
 
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
-					   struct wpa_ssid *ssid)
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
 {
 	u8 key[32];
 	size_t keylen;
@@ -470,6 +472,9 @@
 	wpa_s->disallow_aps_ssid = NULL;
 
 	wnm_bss_keep_alive_deinit(wpa_s);
+#ifdef CONFIG_WNM
+	wnm_deallocate_memory(wpa_s);
+#endif /* CONFIG_WNM */
 
 	ext_password_deinit(wpa_s->ext_pw);
 	wpa_s->ext_pw = NULL;
@@ -1271,7 +1276,6 @@
 	enum wpa_cipher cipher_pairwise, cipher_group;
 	struct wpa_driver_associate_params params;
 	int wep_keys_set = 0;
-	struct wpa_driver_capa capa;
 	int assoc_failed = 0;
 	struct wpa_ssid *old_ssid;
 	u8 ext_capab[10];
@@ -1475,7 +1479,7 @@
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_HS20
-	if (wpa_s->conf->hs20) {
+	if (is_hs20_network(wpa_s, ssid, bss)) {
 		struct wpabuf *hs20;
 		hs20 = wpabuf_alloc(20);
 		if (hs20) {
@@ -1686,8 +1690,8 @@
 		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
 	}
 
-	if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
-	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
+	if (wep_keys_set &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
 		/* Set static WEP keys again */
 		wpa_set_wep_keys(wpa_s, ssid);
 	}
@@ -1821,7 +1825,8 @@
 			wpa_supplicant_cancel_sched_scan(wpa_s);
 		}
 
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		if (wpa_supplicant_fast_associate(wpa_s) != 1)
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
 }
 
@@ -2344,7 +2349,10 @@
 		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
 		if (addr)
 			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-	} else if (!(wpa_s->drv_flags &
+	} else if ((!wpa_s->p2p_mgmt ||
+		    !(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+		   !(wpa_s->drv_flags &
 		     WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
 		l2_packet_deinit(wpa_s->l2);
 		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
@@ -2364,10 +2372,6 @@
 		return -1;
 	}
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
-		MAC2STR(wpa_s->own_addr));
-	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
 	return 0;
 }
 
@@ -2413,6 +2417,10 @@
 	if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
 		return -1;
 
+	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+		MAC2STR(wpa_s->own_addr));
+	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
 	if (wpa_s->bridge_ifname[0]) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
 			"interface '%s'", wpa_s->bridge_ifname);
@@ -2851,6 +2859,11 @@
 			wpa_s->conf->driver_param =
 				os_strdup(iface->driver_param);
 		}
+
+		if (iface->p2p_mgmt && !iface->ctrl_interface) {
+			os_free(wpa_s->conf->ctrl_interface);
+			wpa_s->conf->ctrl_interface = NULL;
+		}
 	} else
 		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
 						     iface->driver_param);
@@ -2976,11 +2989,24 @@
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;
 
+	/*
+	 * Only take p2p_mgmt parameters when P2P Device is supported.
+	 * Doing it here as it determines whether l2_packet_init() will be done
+	 * during wpa_supplicant_driver_init().
+	 */
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+		wpa_s->p2p_mgmt = iface->p2p_mgmt;
+	else
+		iface->p2p_mgmt = 1;
+
 	if (wpa_supplicant_driver_init(wpa_s) < 0)
 		return -1;
 
 #ifdef CONFIG_TDLS
-	if (wpa_tdls_init(wpa_s->wpa))
+	if ((!iface->p2p_mgmt ||
+	     !(wpa_s->drv_flags &
+	       WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+	    wpa_tdls_init(wpa_s->wpa))
 		return -1;
 #endif /* CONFIG_TDLS */
 
@@ -3018,7 +3044,7 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+	if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
 		return -1;
 	}
@@ -3027,6 +3053,20 @@
 	if (wpa_bss_init(wpa_s) < 0)
 		return -1;
 
+#ifdef CONFIG_EAP_PROXY
+{
+	size_t len;
+	wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &len);
+	if (wpa_s->mnc_len > 0) {
+		wpa_s->imsi[len] = '\0';
+		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+			   wpa_s->imsi, wpa_s->mnc_len);
+	} else {
+		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+	}
+}
+#endif /* CONFIG_EAP_PROXY */
+
 	if (pcsc_reader_init(wpa_s) < 0)
 		return -1;
 
@@ -3040,6 +3080,7 @@
 static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 					int notify, int terminate)
 {
+	wpa_s->disconnected = 1;
 	if (wpa_s->drv_priv) {
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
@@ -3076,6 +3117,8 @@
 		wpa_config_free(wpa_s->conf);
 		wpa_s->conf = NULL;
 	}
+
+	os_free(wpa_s);
 }
 
 
@@ -3126,14 +3169,12 @@
 		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
 			   iface->ifname);
 		wpa_supplicant_deinit_iface(wpa_s, 0, 0);
-		os_free(wpa_s);
 		return NULL;
 	}
 
 	/* Notify the control interfaces about new iface */
 	if (wpas_notify_iface_added(wpa_s)) {
 		wpa_supplicant_deinit_iface(wpa_s, 1, 0);
-		os_free(wpa_s);
 		return NULL;
 	}
 
@@ -3186,7 +3227,6 @@
 	if (global->p2p_invite_group == wpa_s)
 		global->p2p_invite_group = NULL;
 	wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
-	os_free(wpa_s);
 
 	return 0;
 }
@@ -3306,6 +3346,9 @@
 	if (params->ctrl_interface)
 		global->params.ctrl_interface =
 			os_strdup(params->ctrl_interface);
+	if (params->ctrl_interface_group)
+		global->params.ctrl_interface_group =
+			os_strdup(params->ctrl_interface_group);
 	if (params->override_driver)
 		global->params.override_driver =
 			os_strdup(params->override_driver);
@@ -3415,9 +3458,6 @@
 #ifdef CONFIG_WIFI_DISPLAY
 	wifi_display_deinit(global);
 #endif /* CONFIG_WIFI_DISPLAY */
-#ifdef CONFIG_P2P
-	wpas_p2p_deinit_global(global);
-#endif /* CONFIG_P2P */
 
 	while (global->ifaces)
 		wpa_supplicant_remove_iface(global, global->ifaces, 1);
@@ -3448,6 +3488,7 @@
 		os_free(global->params.pid_file);
 	}
 	os_free(global->params.ctrl_interface);
+	os_free(global->params.ctrl_interface_group);
 	os_free(global->params.override_driver);
 	os_free(global->params.override_ctrl_interface);
 
@@ -3596,6 +3637,12 @@
 	 */
 	count += wpa_s->extra_blacklist_count;
 
+	if (count > 3 && wpa_s->current_ssid) {
+		wpa_printf(MSG_DEBUG, "Continuous association failures - "
+			   "consider temporary network disabling");
+		wpas_auth_failed(wpa_s);
+	}
+
 	switch (count) {
 	case 1:
 		timeout = 100;
@@ -3871,3 +3918,42 @@
 	if (wpa_supplicant_fast_associate(wpa_s) != 1)
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
+
+
+/**
+ * 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)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+
+	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;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 0935a06..d73d371 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -310,6 +310,10 @@
 # allowing it to update the internal BSS table.
 #ignore_old_scan_res=0
 
+# scan_cur_freq: Whether to scan only the current frequency
+# 0:  Scan all available frequencies. (Default)
+# 1:  Scan current operating frequency if another VIF on the same radio
+#     is already associated.
 
 # Interworking (IEEE 802.11u)
 
@@ -524,6 +528,9 @@
 # set, scan results that do not match any of the specified frequencies are not
 # considered when selecting a BSS.
 #
+# This can also be set on the outside of the network block. In this case,
+# it limits the frequencies that will be scanned.
+#
 # bgscan: Background scanning
 # wpa_supplicant behavior for background scanning can be specified by
 # configuring a bgscan module. These modules are responsible for requesting
@@ -808,6 +815,11 @@
 #	interface used for EAPOL. The default value is suitable for most
 #	cases.
 #
+# ocsp: Whether to use/require OCSP to check server certificate
+#	0 = do not use OCSP stapling (TLS certificate status extension)
+#	1 = try to use OCSP stapling, but not require response
+#	2 = require valid OCSP stapling response
+#
 # EAP-FAST variables:
 # pac_file: File path for the PAC entries. wpa_supplicant will need to be able
 #	to create this file and write updates to it when PAC is being
@@ -1231,3 +1243,10 @@
 network={
 	key_mgmt=NONE
 }
+
+
+# Example config file that will only scan on channel 36.
+freq_list=5180
+network={
+	key_mgmt=NONE
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index f96b245..9240863 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -104,6 +104,15 @@
 	 * receiving of EAPOL frames from an additional interface.
 	 */
 	const char *bridge_ifname;
+
+	/**
+	 * p2p_mgmt - Interface used for P2P management (P2P Device operations)
+	 *
+	 * Indicates whether wpas_p2p_init() must be called for this interface.
+	 * This is used only when the driver supports a dedicated P2P Device
+	 * interface that is not a network interface.
+	 */
+	int p2p_mgmt;
 };
 
 /**
@@ -155,6 +164,11 @@
 	char *ctrl_interface;
 
 	/**
+	 * ctrl_interface_group - Global ctrl_iface group
+	 */
+	char *ctrl_interface_group;
+
+	/**
 	 * dbus_ctrl_interface - Enable the DBus control interface
 	 */
 	int dbus_ctrl_interface;
@@ -348,6 +362,8 @@
 	struct wpa_ssid_value *disallow_aps_ssid;
 	size_t disallow_aps_ssid_count;
 
+	enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;
+
 	/* previous scan was wildcard when interleaving between
 	 * wildcard scans and specific SSID scan when max_ssids=1 */
 	int prev_scan_wildcard;
@@ -400,10 +416,8 @@
 			     * previous association event */
 
 	struct scard_data *scard;
-#ifdef PCSC_FUNCS
 	char imsi[20];
 	int mnc_len;
-#endif /* PCSC_FUNCS */
 
 	unsigned char last_eapol_src[ETH_ALEN];
 
@@ -561,6 +575,8 @@
 	unsigned int roc_waiting_drv_freq;
 	int action_tx_wait_time;
 
+	int p2p_mgmt;
+
 #ifdef CONFIG_P2P
 	struct p2p_go_neg_results *go_params;
 	int create_p2p_iface;
@@ -690,6 +706,22 @@
 	u8 last_gas_dialog_token;
 
 	unsigned int no_keep_alive:1;
+
+#ifdef CONFIG_WNM
+	u8 wnm_dialog_token;
+	u8 wnm_reply;
+	u8 wnm_num_neighbor_report;
+	u8 wnm_mode;
+	u16 wnm_dissoc_timer;
+	u8 wnm_validity_interval;
+	u8 wnm_bss_termination_duration[12];
+	struct neighbor_report *wnm_neighbor_report_elements;
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_TESTING_GET_GTK
+	u8 last_gtk[32];
+	size_t last_gtk_len;
+#endif /* CONFIG_TESTING_GET_GTK */
 };
 
 
@@ -702,6 +734,8 @@
 	struct wpa_driver_associate_params *params);
 
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid);
 
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
 
@@ -780,6 +814,7 @@
 		    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
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index cd51873..61a42bd 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -437,6 +437,13 @@
 		/* Clear the MIC error counter when setting a new PTK. */
 		wpa_s->mic_errors_seen = 0;
 	}
+#ifdef CONFIG_TESTING_GET_GTK
+	if (key_idx > 0 && addr && is_broadcast_ether_addr(addr) &&
+	    alg != WPA_ALG_NONE && key_len <= sizeof(wpa_s->last_gtk)) {
+		os_memcpy(wpa_s->last_gtk, key, key_len);
+		wpa_s->last_gtk_len = key_len;
+	}
+#endif /* CONFIG_TESTING_GET_GTK */
 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
 			       key, key_len);
 }
@@ -506,8 +513,6 @@
 }
 #endif /* CONFIG_IEEE80211R */
 
-#endif /* CONFIG_NO_WPA */
-
 
 #ifdef CONFIG_TDLS
 
@@ -551,7 +556,7 @@
 
 
 static int wpa_supplicant_tdls_peer_addset(
-	void *ctx, const u8 *peer, int add, u16 capability,
+	void *ctx, const u8 *peer, int add, u16 aid, u16 capability,
 	const u8 *supp_rates, size_t supp_rates_len,
 	const struct ieee80211_ht_capabilities *ht_capab,
 	const struct ieee80211_vht_capabilities *vht_capab,
@@ -563,7 +568,7 @@
 	os_memset(&params, 0, sizeof(params));
 
 	params.addr = peer;
-	params.aid = 1;
+	params.aid = aid;
 	params.capability = capability;
 	params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
 
@@ -589,6 +594,8 @@
 
 #endif /* CONFIG_TDLS */
 
+#endif /* CONFIG_NO_WPA */
+
 
 enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
 {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9af6084..8e0207c 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -219,6 +219,80 @@
 }
 
 
+static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *new_ssid)
+{
+	struct wpa_ssid *ssid, *next;
+
+	for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
+	     ssid = next, next = ssid ? ssid->next : NULL) {
+		/*
+		 * new_ssid has already been added to the list in
+		 * wpas_wps_add_network(), so skip it.
+		 */
+		if (ssid == new_ssid)
+			continue;
+
+		if (ssid->bssid_set || new_ssid->bssid_set) {
+			if (ssid->bssid_set != new_ssid->bssid_set)
+				continue;
+			if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
+			    0)
+				continue;
+		}
+
+		/* compare SSID */
+		if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
+			continue;
+
+		if (ssid->ssid && new_ssid->ssid) {
+			if (os_memcmp(ssid->ssid, new_ssid->ssid,
+				      ssid->ssid_len) != 0)
+				continue;
+		} else if (ssid->ssid || new_ssid->ssid)
+			continue;
+
+		/* compare security parameters */
+		if (ssid->auth_alg != new_ssid->auth_alg ||
+		    ssid->key_mgmt != new_ssid->key_mgmt ||
+		    ssid->proto != new_ssid->proto ||
+		    ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
+		    ssid->group_cipher != new_ssid->group_cipher)
+			continue;
+
+		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);
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+	}
+}
+
+
 static int wpa_supplicant_wps_cred(void *ctx,
 				   const struct wps_credential *cred)
 {
@@ -438,6 +512,8 @@
 	if (cred->ap_channel)
 		wpa_s->wps_ap_channel = cred->ap_channel;
 
+	wpas_wps_remove_dup_network(wpa_s, ssid);
+
 #ifndef CONFIG_NO_CONFIG_WRITE
 	if (wpa_s->conf->update_config &&
 	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -572,6 +648,9 @@
 	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
 	wpa_s->wps_success = 1;
 	wpas_notify_wps_event_success(wpa_s);
+	if (wpa_s->current_ssid)
+		wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
+	wpa_s->extra_blacklist_count = 0;
 
 	/*
 	 * Enable the networks disabled during wpas_wps_reassoc after 10
@@ -789,9 +868,8 @@
 	while (ssid) {
 		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
 			if (ssid == wpa_s->current_ssid) {
-				wpa_s->current_ssid = NULL;
-				if (ssid != NULL)
-					wpas_notify_network_changed(wpa_s);
+				wpa_supplicant_deauthenticate(
+					wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 			}
 			id = ssid->id;
 			remove_ssid = ssid;
@@ -888,21 +966,10 @@
 }
 
 
-static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
-			     struct wpa_ssid *selected, const u8 *bssid)
+static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *selected)
 {
 	struct wpa_ssid *ssid;
-	struct wpa_bss *bss;
-
-	wpa_s->after_wps = 0;
-	wpa_s->known_wps_freq = 0;
-	if (bssid) {
-		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
-		if (bss && bss->freq > 0) {
-			wpa_s->known_wps_freq = 1;
-			wpa_s->wps_freq = bss->freq;
-		}
-	}
 
 	if (wpa_s->current_ssid)
 		wpa_supplicant_deauthenticate(
@@ -930,6 +997,26 @@
 		}
 		ssid = ssid->next;
 	}
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *selected, const u8 *bssid)
+{
+	struct wpa_bss *bss;
+
+	wpa_s->after_wps = 0;
+	wpa_s->known_wps_freq = 0;
+	if (bssid) {
+		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+		if (bss && bss->freq > 0) {
+			wpa_s->known_wps_freq = 1;
+			wpa_s->wps_freq = bss->freq;
+		}
+	}
+
+	wpas_wps_temp_disable(wpa_s, selected);
+
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 	wpa_s->scan_runs = 0;
@@ -2011,6 +2098,15 @@
 {
 	wpa_s->wps_ap_channel = 0;
 
+	/*
+	 * Disable existing networks temporarily to allow the newly learned
+	 * credential to be preferred. Enable the temporarily disabled networks
+	 * after 10 seconds.
+	 */
+	wpas_wps_temp_disable(wpa_s, NULL);
+	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+			       NULL);
+
 	if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
 		return -1;